POJ3694 Network(tarjan求桥)
给出一个无向连通图,问加入边的过程中,桥的个数。
先用tarjan算法求出桥的总数,标记每个桥的终点。
每加入两个顶点,就查询两个顶点的lca,把lca路径上的桥都剪掉~
链式前向星:
#include<cstdio> #include<algorithm> #include<vector> #include<stack> #include<cstring> using namespace std; const int maxn=1e6+10; int N,M,x,y; int head[maxn]; int tol; struct node { int u,v,next; }edge[maxn]; void addedge (int u,int v) { edge[tol].u=u; edge[tol].v=v; edge[tol].next=head[u]; head[u]=tol++; } int low[maxn]; int dfn[maxn]; int q; int pos[maxn]; int dep[maxn]; int father[maxn]; int bridge[maxn]; int depth[maxn]; int cnt; int scc; int ans; stack<int> st; void init () { fill(low,low+maxn,0); fill(dfn,dfn+maxn,0); fill(pos,pos+maxn,0); fill(depth,depth+maxn,0); fill(father,father+maxn,0); fill(bridge,bridge+maxn,0); memset(head,-1,sizeof(head)); tol=0; cnt=0; scc=0; ans=0; } void tarjan (int x,int pre) { low[x]=dfn[x]=++cnt; depth[x]=depth[pre]+1; for (int i=head[x];i!=-1;i=edge[i].next) { int v=edge[i].v; if (v==pre) continue; if (!low[v]) { father[v]=x; tarjan(v,x); low[x]=min(low[x],low[v]); if (low[v]>dfn[x]) { ans++; bridge[v]=1; } } else if (!pos[v]) low[x]=min(low[x],dfn[v]); } } void lca (int u,int v) { while (depth[u]<depth[v]) { if (bridge[v]) { bridge[v]=0; ans--; } v=father[v]; } while (depth[u]>depth[v]) { if (bridge[u]) { bridge[u]=0; ans--; } u=father[u]; } while (u!=v) { if (bridge[u]) { bridge[u]=0; ans--; } if (bridge[v]) { bridge[v]=0; ans--; } u=father[u]; v=father[v]; } } int main () { int t=1; while (~scanf("%d%d",&N,&M)) { if (N==0&&M==0) break; init(); for (int i=0;i<M;i++) { scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } for (int i=1;i<=N;i++) if (!low[i]) tarjan(i,i); scanf("%d",&q); printf("Case %d:\n",t++); while (q--) { scanf("%d%d",&x,&y); lca(x,y); printf("%d\n",ans); } } return 0; }
邻接表:
#include<cstdio> #include<algorithm> #include<vector> #include<stack> #include<cstring> using namespace std; const int maxn=1e6+14; vector<int> g[maxn]; int N,M,x,y; int low[maxn]; int dfn[maxn]; int q; int pos[maxn]; int depth[maxn]; int father[maxn]; int bridge[maxn]; int cnt; int scc; int ans; stack<int> st; void init () { fill(low,low+maxn,0); fill(dfn,dfn+maxn,0); fill(pos,pos+maxn,0); fill(depth,depth+maxn,0); fill(father,father+maxn,0); fill(bridge,bridge+maxn,0); for (int i=0;i<maxn;i++) g[i].clear(); while (!st.empty()) st.pop(); cnt=0; scc=0; ans=0; } void tarjan (int x,int pre) { low[x]=dfn[x]=++cnt; depth[x]=depth[pre]+1; for (int i=0;i<g[x].size();i++) { if (g[x][i]==pre) continue; if (!low[g[x][i]]) { father[g[x][i]]=x; tarjan(g[x][i],x); low[x]=min(low[x],low[g[x][i]]); if (low[g[x][i]]>dfn[x]) { ans++; bridge[g[x][i]]=1; } } else if (!pos[g[x][i]]) low[x]=min(low[x],dfn[g[x][i]]); } } void lca (int u,int v) { while (depth[u]<depth[v]) { if (bridge[v]) { bridge[v]=0; ans--; } v=father[v]; } while (depth[u]>depth[v]) { if (bridge[u]) { bridge[u]=0; ans--; } u=father[u]; } while (u!=v) { if (bridge[u]) { bridge[u]=0; ans--; } if (bridge[v]) { bridge[v]=0; ans--; } u=father[u]; v=father[v]; } } int main () { int t=1; while (~scanf("%d %d",&N,&M)) { if (N==0&&M==0) break; init (); for (int i=0;i<M;i++) { scanf ("%d %d",&x,&y); g[x].push_back(y); g[y].push_back(x); } for (int i=1;i<=N;i++) if (!low[i]) tarjan(i,i); scanf("%d",&q); printf ("Case %d:\n",t++); while (q--) { scanf ("%d %d",&x,&y); lca (x,y); printf ("%d\n",ans); } } return 0; }