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;
}
浙公网安备 33010602011771号