poj 3177 双连通

题大意:给出n个点,编号1~n,给出至少n-1条边。问在需要增加几条边是该图成为双连通图。

因为至少有n-1条边,所以一定是连通图,利用tarjan算法找出双连通分量,如果我们把每个双连通分量看成一个顶点,那么就构成了一棵树,再求出叶子的个数m,(m+1)/2就是答案了。我不解的是这道题需要除去重边才能AC........

代码如下:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
vector <int> map[5001];
int pre[5001],low[5001],degree[5001],visit[5001],cnt,count;
int dfs(int i,int parent)
{
	int j,k;
	pre[i]=cnt++;
	low[i]=pre[i];
	for(j=0;j<map[i].size();j++)
	{
		k=map[i].at(j);
		if(pre[k]==-1)
		{
			dfs(k,i);
			if(low[i]>low[k]) low[i]=low[k];
		}
		else if(k!=parent)
		{
			if(low[i]>low[k]) low[i]=low[k];
		}
	}
	return 0;
}
int search(int s,int t)
{
	int i;
	for(i=0;i<map[s].size();i++)
		if(map[s][i]==t) return 0;
	return 1;
}
int main()
{
	int i,j,k,m,n,s,t;
	while(cin>>m>>n)
	{
		for(i=0;i<n;i++)
		{
			cin>>s>>t;
			if(search(s,t))
			{
			    map[s].push_back(t);
		    	map[t].push_back(s);
			}
		}
		cnt=1;count=0;
		for(i=1;i<=m;i++)
			pre[i]=-1;
		memset(low,0,sizeof(low));
		dfs(1,0);
		memset(degree,0,sizeof(degree));
		for(i=1;i<=m;i++)
			for(j=0;j<map[i].size();j++)
			{
				k=map[i][j];
				if(low[i]!=low[k]) degree[low[k]]++;
			}
			memset(visit,0,sizeof(visit));
			for(i=1;i<=m;i++)
				if(degree[low[i]]==1 && !visit[low[i]])
				{
					count++;
					visit[low[i]]=1;
				}
				cout<<(count+1)/2<<endl;
				for(i=0;i<=m;i++)
					map[i].clear();
	}
	return 0;
}
posted @ 2011-07-24 19:18  书山有路,学海无涯  阅读(324)  评论(0编辑  收藏  举报