题目:
原本没有记录桥是谁,而是染色时即时判断的。后来发现不行,因为a去b可能满足low[b]>dfn[a],但b去a就不满足了。
这是因为low和dfn的关系是相对的,仅限于tarjan时的那棵dfs搜索树中。染色时没有按那棵树走,就不能用dfn和low了!
累加ans时可以把边+=2,很方便。
别忘了写v=edge[i].to。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,r,head[5005],xnt=1,dfn[5005],low[5005],col[5005]; int x,y,tim,cnt,d[5005],ans; bool b[5005][5005],brg[20005]; struct Edge{ int next,to,from; Edge(int n=0,int t=0,int f=0):next(n),to(t),from(f) {} }edge[20005]; void dfs(int cur,int fa) { // printf("cur=%d ",cur); dfn[cur]=low[cur]=++tim; for(int i=head[cur],v;i;i=edge[i].next) { if(dfn[v=edge[i].to]&&v!=fa) low[cur]=min(low[cur],dfn[v]); if(!dfn[v]) { dfs(v,cur); low[cur]=min(low[cur],low[v]); if(low[v]>dfn[cur])brg[i]=1,brg[i^1]=1; } } // printf("cur=%d dfn=%d low=%d ",cur,dfn[cur],low[cur]); } void cl(int cur,int fa) { col[cur]=cnt; // printf("cur=%d col=%d ",cur,cnt); for(int i=head[cur],v;i;i=edge[i].next) { if(edge[i].to==fa||brg[i])continue; // printf("v=%d lowv=%d dfncur=%d ",edge[i].to,low[edge[i].to],dfn[cur]); // if(low[v=edge[i].to]<=dfn[cur]&&!col[v])cl(v,cur);//避免环的死循环 //a去b是桥,b去a就不一定了 if(!col[v=edge[i].to])cl(v,cur);// } } int main() { // freopen("POJ3177.in","r",stdin); // freopen("poj3177.out","w",stdout); // while(1) // { // xnt=1;cnt=0;ans=0;tim=0; // memset(b,0,sizeof b); // memset(col,0,sizeof col); // memset(dfn,0,sizeof dfn); // memset(low,0,sizeof low); // memset(head,0,sizeof head); // memset(d,0,sizeof d); // memset(brg,0,sizeof brg); scanf("%d%d",&n,&r); for(int i=1;i<=r;i++) { scanf("%d%d",&x,&y); if(!b[x][y]) { b[x][y]=1;b[y][x]=1; edge[++xnt]=Edge(head[x],y,x);head[x]=xnt; edge[++xnt]=Edge(head[y],x,y);head[y]=xnt; } } dfs(1,0); for(int i=1;i<=n;i++) if(!col[i]) { cnt++;cl(i,0); } for(int i=2;i<=xnt;i+=2) if(col[edge[i].from]!=col[edge[i].to]) // if(brg[i]) { d[col[edge[i].from]]++;d[col[edge[i].to]]++; // brg[i]=0; // brg[i^1]=0; } for(int i=1;i<=cnt;i++) if(d[i]==1)ans++; printf("%d ",(ans+1)/2); // } return 0; }