题意:
给一个无向图,问你需要添加多少条边之后这个图变成双连通分量。
关于桥和双连通分量之类的可以参看以下链接。
http://www.byvoid.com/blog/biconnect/ 和http://blog.csdn.net/geniusluzh/article/details/6619575
思路:
/*一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)。*/
#include<iostream> #define min(a,b) (a<b?a:b) using namespace std; const int N=1005,M=2005; int n,m; struct Edge { int v,next; }edge[M]; int edgehead[N]; int k=1; void addedge(int u,int v) { edge[k].next=edgehead[u]; edge[k].v=v; edgehead[u]=k++; } int dfn[N]; int low[N]; int index; void tarjan(int i,int fa)//注意与求强连通分量时的tarjan算法的区别。 { dfn[i]=low[i]=index++; for(int j=edgehead[i];j;j=edge[j].next) { int v=edge[j].v; if(!dfn[v]) { tarjan(v,i); low[i]=min(low[i],low[v]); } else if(v!=fa)//这里的区别,不需要考虑是否在栈内。 { low[i]=min(low[i],dfn[v]); } } } int degree[N]; void solve() { tarjan(1,-1);//因为给定的图已经是强连通图。 for(int i=1;i<=n;i++) { for(int j=edgehead[i];j;j=edge[j].next) { int v=edge[j].v; if(low[v]!=low[i])//在同一个双连通分量里面的low值相等 { degree[low[i]]++;//间接缩点了,记得这里不是degree[i]++; degree[low[v]]++; } } } int ans=0; for(int i=1;i<=n;i++) { if(degree[i]==2) ans++; } printf("%d\n",(ans+1)/2);//这里要注意,因为缩点后是一棵树,双连通分量是树的叶子节点的数目+1除2。 } int main() { while(scanf("%d%d",&n,&m)!=EOF) { index=1; memset(edge,0,sizeof(edge)); memset(edgehead,0,sizeof(edgehead)); k=1; memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(degree,0,sizeof(degree)); int from,to; for(int i=1;i<=m;i++) { scanf("%d%d",&from,&to); addedge(from,to); addedge(to,from); } solve(); } return 0; }