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;

}

你可能感兴趣的:(poj)