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; }