给你一个无向连通图,每次加一条边后,问图中桥的数目
两种解法:
1.求双连通分量,利用并查集缩点,形成一棵树,树边肯定都是桥,然后每对点x,y,找原图中x,y点对应的新图中的点,如果不是一个点,则向上找它们的LCA,因为它们之间连了一条边,所以这些点到它们的LCA之间的边都不是割边了,找LCA时,先将两点上升到同一层次,然后一起再向上找父亲节点,其间遇到桥就把桥的标记删除,并且答案减1
2.不缩点,直接在原图中找LCA,求桥时记录每个节点的父亲节点和层次,根据这两样信息,用解法1中的方法去找LCA
代码:
解法一
#include #include #include using namespace std; const int MAX=100005; struct node { int v,next; }g[MAX*10],gg[MAX*10]; int e,ee,n,m,q,index,cnt; int adj[MAX],dfn[MAX],low[MAX],fa[MAX],vis[MAX],adj2[MAX],level[MAX],pre[MAX],res[MAX]; bool bridge[MAX]; int min(int a,int b) { return alevel[v]) { if(bridge[u]) { cnt--; bridge[u]=0; } u=pre[u]; } while(level[v]>level[u]) { if(bridge[v]) { cnt--; bridge[v]=0; } v=pre[v]; } while(u!=v) { if(bridge[u]) { cnt--; bridge[u]=0; } if(bridge[v]) { cnt--; bridge[v]=0; } u=pre[u]; v=pre[v]; } } int main() { int ca=0,i,j; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; memset(adj,-1,sizeof(adj)); memset(adj2,-1,sizeof(adj2)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(bridge,false,sizeof(bridge)); memset(level,0,sizeof(level)); e=ee=index=cnt=0; while(m--) { scanf("%d%d",&i,&j); add(i,j); add(j,i); } for(i=1;i<=n;i++) fa[i]=i; for(i=1;i<=n;i++) if(!vis[i]) tarjan(i,-1); for(int u=1;u<=n;u++) { for(int k=adj[u];k!=-1;k=g[k].next) { int v=g[k].v; i=find(u); j=find(v); if(i!=j) add2(i,j); } } memset(vis,0,sizeof(vis)); lca_dfs(fa[1],1); for(i=1;i<=cnt;i++) bridge[find(g[res[i]].v)]=1; printf("Case %d:/n",++ca); scanf("%d",&q); while(q--) { scanf("%d%d",&i,&j); int x=find(i),y=find(j); if(x!=y) lca(x,y); printf("%d/n",cnt); } printf("/n"); } return 0; }
解法二
/* Low(u)=Min { DFS(u) DFS(v) (u,v)为后向边(返祖边) 等价于 DFS(v) #include #include using namespace std; const int MAX=100005; struct node { int v,next; }g[MAX*10]; int e,ee,n,m,q,index,cnt; int adj[MAX],dfn[MAX],low[MAX],fa[MAX],vis[MAX]; bool bridge[MAX]; int min(int a,int b) { return adfn[v])//公共祖先的发现时间一定不大于min(dfn[u],dfn[v]) { if(bridge[u]) { cnt--; bridge[u]=false; } u=fa[u]; } while(dfn[v]>dfn[u]) { if(bridge[v]) { cnt--; bridge[v]=false; } v=fa[v]; } while(u!=v) { if(bridge[u]) { cnt--; bridge[u]=false; } if(bridge[v]) { cnt--; bridge[v]=false; } u=fa[u]; v=fa[v]; } } int main() { int ca=0,i,j; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; memset(adj,-1,sizeof(adj)); //memset(adj2,-1,sizeof(adj2)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(bridge,false,sizeof(bridge)); e=ee=index=cnt=0; while(m--) { scanf("%d%d",&i,&j); add(i,j); add(j,i); } for(i=1;i<=n;i++) if(!vis[i]) tarjan(i); scanf("%d",&q); printf("Case %d:/n",++ca); while(q--) { scanf("%d%d",&i,&j); lca(i,j); cout<