poj1966 - Cable TV Network

                                  想看更多的解題報告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                  轉載請註明出處:http://blog.csdn.net/wangjian8006

 

題目大意:給你一個無向圖,這個圖有一個安全係數f,
f的定義是:
1.f爲n,如果不管刪除多少個頂點,剩下的圖仍然是連通的
2.f爲刪除最少的頂點數,使得剩下的圖不連通
給你一個圖,求出f


解題思路:題目給出的目標很明顯,轉換成圖,那麼f就是無向圖中的連通度嗎,或者說,是求無向圖中的最小割點集。
根據Menger定理,這樣建圖,首先將每個點拆成兩個點
每個點可以表示成i與i+n

那麼有向邊<i,i+n>的容量爲1
如果i與j相鄰,那麼有有向邊<i+n,j>=<j+n,i>=INF,等於無窮大

然後固定源點,枚舉匯點求最大流。如果最大流都是INF,那麼代表這個圖是一個完全連通圖,最小割點集爲n
否則就輸出最大流。

 

 

/*
Memory 272K
Time   47MS
*/

#include <iostream>
#include <queue>
using namespace std;
#define MAXV 110
#define INF 1<<29
#define min(a,b) (a>b?b:a)

int map[MAXV][MAXV],flow[MAXV][MAXV];
int parent[MAXV];			//用於bfs尋找路徑

int bfs(int n,int start,int end){
	int a[MAXV],i,v;
	queue <int>q;

	memset(a,0,sizeof(a));				//記錄增廣路最小流量,而且又可以當做廣搜的標記數組
	memset(parent,-1,sizeof(parent));		//記錄下這條增廣路,以便增流
	
	q.push(start);
	a[start]=INF;
	while(!q.empty()){
		v=q.front();q.pop();
		for(i=0;i<n;i++){
			if(!a[i] && map[v][i]>flow[v][i]){		//如果這是一條允許弧就記錄下來
				q.push(i);
				parent[i]=v;
				a[i]=min(a[v],map[v][i]-flow[v][i]);
			}
		}
		if(v==end) break;				//找到增廣路退出
	}
	return a[end];
}

int EdmondsKarp(int n,int sp,int fp){
	int i,tmp;
	int maxflow=0;
	memset(flow,0,sizeof(flow));
	while(tmp=bfs(n,sp,fp)){
		for(i=fp;i!=sp;i=parent[i]){				//根據父親數組更新流量
			flow[i][parent[i]]-=tmp;			//更新反向流
			flow[parent[i]][i]+=tmp;			//更新正向流
		}
		maxflow+=tmp;
	}
	return maxflow;
}

int main(){
	int i,a,b;
	int n,m;
	while(~scanf("%d %d",&n,&m)){
		memset(map,0,sizeof(map));
		for(i=0;i<n;i++) map[i][i+n]=1;
		for(i=0;i<m;i++){
			scanf(" (%d,%d)",&a,&b);
			map[a+n][b]=map[b+n][a]=INF;
		}
		
		int ans=INF;
		for(i=1;i<n;i++){
			ans=min(ans,EdmondsKarp(n*2,n,i));
		}
		
		if(ans==INF) printf("%d\n",n);
		else printf("%d\n",ans);
	}
	return 0;
}


 

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