hdu 4654 k-edge connected components

k-edge connected components

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 41    Accepted Submission(s): 25


Problem Description
Efficiently computing k-edge connected components in a large graph G = (V, E), where V is the vertex set and E is the edge set, is a long standing research problem. It is not only fundamental in graph analysis but also crucial in graph search optimization algorithms. Computing k-edge connected components has many real applications. For example, in social networks, computing k-edge connected components can identify the closely related entities to provide useful information for social behavior mining. In a web-link based graph, a highly connected graph may be a group of web pages with a high commonality, which is useful for identifying the similarities among web pages. In computational biology, a highly connected subgraph is likely to be a functional cluster of genes for biologist to conduct the study of gene microarrays. Computing k-edge connected components also potentially contributes to many other technology developments such as graph visualization, robust detection of communication networks, community detection in a social network.

Clearly, if a graph G is not k-edge connected, there must be a set C of edges, namely a cut, such that the number |C| of edges in C is smaller than k and the removal of the edges in C cuts the graph G into two disconnected subgraphs G1 and G2. A connected component is a maximal connected subgraph of G. Note that each vertex belongs to exactly one connected component, as does each edge.

Now, we give you a undirected graph G with n vertices and m edges without self-loop or multiple edge, your task is just find out the number of k-edge connected components in G.
 

Input
Multicases. 3 integer numbers n, m and k are described in the first line of the testcase.(3≤n≤100, 1≤m≤n×(n-1)/2,2≤k≤n)The following m lines each line has 2 numbers u, v describe the edges of graph G.(1≤u,v≤n,u≠v)
 

Output
A single line containing the answer to the problem.
 

Sample Input
5 6 3 1 3 2 3 1 4 2 4 1 5 2 5 9 11 2 1 2 1 3 2 3 4 5 4 6 5 6 7 8 7 9 8 9 1 4 1 7 16 30 3 1 2 1 3 1 4 2 3 2 4 3 4 5 6 5 7 5 8 6 7 6 8 7 8 9 10 9 11 9 12 10 11 10 12 11 12 13 14 13 15 13 16 14 15 14 16 15 16 1 5 2 6 1 9 2 10 1 13
2 14

Sample Output
5 3 4

 題目大意:

找出k聯通分量的個數,k聯通分量的意思是全局最小割的大小大於等於k。

解題思路:

Stoer-Wagner算法可以O(n^3)求全局最小割,一次Stoer-Wagner可以求出來當前圖的全局最小割cut,如果cut>=k那麼當前圖就是k聯通分量了,返回1;否則按照SW算法求出來的最小割來把當前圖一分爲二,遞歸下去求這兩個圖的k聯通分量的個數。
僞代碼:
Solve(G)
cut<--Stoer-Wagner(G)
if cut < k return 1
else return solve(G1)+solve(G2)


關於Stoer-Wagner算法:

求全局最小割的算法很簡單且容易證明,首先算法基於一個事實,對於圖G,如果我們知道S,T兩點的最小割記爲s-t-cut,那麼這個s-t-cut可能是G的全局最小割也可能不是。如果不是的話,我們即使把這兩個點合併也不會影響答案,所以就把這兩個點合併好了。這樣n-1次之後就可以把G縮爲一個點了,這個過程中一定可以求出來正解。


所以我們可以每次隨便找兩個點s,t求它們的最小割,然後更新答案,然後把這兩個點合併,直到剩一個點爲止。

找S-T-CUT的方法類似求最大生成樹,具體還是看這個論文:http://docs.google.com/fileview?id=0BwxLvD9mcDNtMjk3MWVkMTAtZjMzNi00ZWE3LTkxYjQtYTQwNzcyZTk3Njk2&hl=en

還有這個博客:http://www.cppblog.com/RyanWang/archive/2009/08/18/93748.html

代碼:

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;

const int INF = 1000000;
const int N  = 110;
int side[N][N];
int grid[N][N];
int w[N];
bool vis[N];
bool deleted[N];
bool choose[N];
int K;

queue<int>qa,qb;
vector<int>nodes[N];

int prim(int k,int n,int &s,int &t){
	s=0;
	while(deleted[s])s++;
	for(int i=0;i<n;i++){
		w[i]=grid[s][i];
		vis[i]=false;
	}
	vis[s]=true;
	int p;
	int Max;
	for(int i=1;i<k;i++){
		Max=-INF;
		for(int j=0;j<n;j++)if(!vis[j]&&!deleted[j]){
			if(w[j]>Max){
				Max=w[j];p=j;
			}
		}
		if(i==k-2)s=p;
		if(i==k-1)t=p;
		vis[p]=true;
		for(int i=0;i<n;i++)if(!vis[i]&&!deleted[i]){
			w[i]+=grid[i][p];
		}
	}
	return w[t];
}
int stoerwagner(int n){
	if(n<=1)return 0;
	int min_cut=INF,s,t;
	for(int i=0;i<n;i++){
		deleted[i]=false;
		nodes[i].clear();
		nodes[i].push_back(i);
	}
	for(int i=1;i<n;i++){
		int cut=prim(n-i+1,n,s,t); 
		if(cut<min_cut){
			min_cut=cut;
			for(int j=0;j<n;j++)choose[j]=0;
			for(int j=0;j<nodes[t].size();j++)choose[nodes[t][j]]=1;
		}
		for(int i=0;i<nodes[t].size();i++){
			nodes[s].push_back(nodes[t][i]);
		}
		deleted[t]=true;
		for(int i=0;i<n;i++){
			if(i==s)continue;
			if(!deleted[i]){
				grid[s][i]+=grid[t][i];
				grid[i][s]+=grid[i][t];
			}
		}
	}
	for(int i=0;i<n;i++){
		if(choose[i])qa.push(i);
		else qb.push(i);
	}
	return min_cut;
}
int solve(vector<int> a){
	int n=a.size();
	if(n<=1)return 1;
	int t;
	for(int i=0;i<n;i++)for(int j=0;j<n;j++){
		grid[i][j]=side[a[i]][a[j]];
	}
	if(stoerwagner(n)>=K){
		while(!qa.empty())qa.pop();
		while(!qb.empty())qb.pop();
		return 1;
	}
	vector<int>x,y;
	while(!qa.empty()){
		x.push_back(a[qa.front()]);qa.pop();
	}
	while(!qb.empty()){y.push_back(a[qb.front()]);qb.pop();};
	return solve(x)+solve(y);
}
int main(){
	int n,m;
	while(~scanf("%d%d%d",&n,&m,&K)){
		memset(side,0,sizeof(side));
		while(m--){
			int u,v;
			scanf("%d%d",&u,&v);
			u--;v--;
			side[u][v]=side[v][u]=1;
		}
		vector<int>graph;
		for(int i=0;i<n;i++){
			graph.push_back(i);
		}
		printf("%d\n",solve(graph));
	}
}


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