POJ 2125 Destroying The Graph 二分圖 最小點權覆蓋

POJ2125 

題意簡述:給定一個有向圖,要通過某些操作刪除所有的邊,每一次操作可以選擇任意一個節點刪除由其出發的所有邊或者通向它的所有邊,兩個方向有不同的權值。問最小權值和的解決方案,要輸出操作。

乍一看是要用點去覆蓋邊,聯想到二分圖的最小點權覆蓋,通過拆點,我們可以得到二分圖。每個點都拆成兩個點,一個作爲入點,另一個作爲出點。於是我們構建了一個標準的二分圖最小點權覆蓋的模型

解決二分圖最小點權覆蓋的的算法並不複雜,創造一個源點和匯點,源點到左邊的點連邊,容量爲對應點的權值,同理右邊的點向匯點連邊。然後運行最大流,就可以得到最小權值和。

下一步就是輸出解決方案,也就是求最小割邊集。在運行完最大流的殘量網絡中由源點出發BFS所有可以到達的點構成了源點集。對於剩下的邊,如果滿流且一個端點屬於源點集而另一個端點不屬於,則這條邊屬於最小割。

代碼實現比較簡單:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn=110*2,maxm=5000,s=0,INF=9999999;
int n,m,t,cap[maxn][maxn],flow[maxn][maxn],w[maxn];

int augment(int fa[])
{
 int d[maxn];
 memset(d,0,sizeof(d));
 d[s]=INF;
 queue<int>q;q.push(s);
 while(!q.empty())
 	{
 	 int u=q.front();q.pop();
 	 for(int i=s;i<=t;i++)
 	 	{
 	 	 if((d[i]!=0)||(cap[u][i]<=flow[u][i]))continue;
 	 	 d[i]=min(d[u],cap[u][i]-flow[u][i]);
 	 	 q.push(i);
 	 	 fa[i]=u;
 	 	 if(i==t)return d[t];
		}
	} 
 return d[t];
}

int  maxflow()
{ 
  int fa[maxn];
  int ans=0;
  
  while(true)
  	{
  	 int nflow=augment(fa);
  	 if(nflow==0)return ans;
  	 ans+=nflow;
  	 for(int i=t;i!=s;i=fa[i])
  	 	{
  	 	 flow[fa[i]][i]+=nflow;
  	 	 flow[i][fa[i]]-=nflow;
		}
	}
}
vector<int> mincut()
{
 bool vis[maxn];
 memset(vis,0,sizeof(vis));
 vis[s]=true;
 queue<int>q;
 q.push(s);
 while(!q.empty())
 	{
 	 int u=q.front();q.pop();
 	 for(int i=s;i<=t;i++)
 	 	{
 	 	 if((vis[i])||(cap[u][i]<=flow[u][i]))continue;
 	 	 vis[i]=true;
 	 	 q.push(i);
		}
	}
 vector<int>ans;
 for(int i=s;i<=t;i++)
 	if(vis[i])for(int j=s;j<=t;j++)
 				if(!vis[j]&&cap[i][j]==flow[i][j]&&cap[i][j]>0)
 					{
 					 if(i==s){ans.push_back(j);}
 					 if(j==t){ans.push_back(i);}
					}
 return ans;
}

void print(vector<int> vec)
{
 cout<<vec.size()<<endl;
 for(int i=0;i<vec.size();i++)
 	{
 		if(vec[i]<=n)cout<<vec[i]<<" -"<<endl;
 			else cout<<vec[i]-n<<" +"<<endl;
	}
}
int main()
{
 ios::sync_with_stdio(false);
 memset(cap,0,sizeof(cap));memset(flow,0,sizeof(flow));
 cin>>n>>m;
 t=n*2+1;
 for(int i=1;i<=n*2;i++)
 	cin>>w[i];
 for(int i=0;i<m;i++)
 	{
 	 int a,b;
 	 cin>>a>>b;
 	 cap[a][b+n]=INF;
	}
 for(int i=1;i<=n;i++)
 	{
 	 cap[s][i]=w[i+n];
 	 cap[i+n][t]=w[i];
	}
 cout<<maxflow()<<endl;
 print( mincut() );
 return 0;
}

  東北歐賽區的題目還是很給力的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章