<题目链接>
题目大意:
给一个无向图,该图只有一个连通分量。然后查询q次,q < 1000, 求每次查询就增加一条边,求剩余桥的个数。
解题分析:
普通的做法就是在每加一条边后,都找一次桥,但是这样肯定超时。
第一种做法是:缩点,因为如果一条边不是桥那么无论怎么加边他肯定都不会变成桥,这样把连通分量缩成一个点。这样全图所有的边就都是桥,这样的话,我们就在加的边里面去找如果加的边是同一个点,那么,肯定不会减少桥,但是如果不是同一个,那么桥肯定减少。
还有一种做法:因为需要u、v之间直接连一条边,所以u->v的原始路径与新连的这条边构成一个环,所以u->v原始路径上的所有桥将不复存在。我们可以先利用Tarjan处理出原图中所有的桥,然后再利用LCA将u->v原始路径的每一条边都求出来(求出u到LCA的所有边和v到LCA的所有边),然后判断该边是否是桥即可,如果是桥,则删除该边的桥标记即可。
下面介绍第二种做法:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 #define clr(a,b) memset(a,b,sizeof(a)) 7 const int N = 1e5+10; 8 const int M = 4e5+10; 9 int n,m,q,tot,index,bridge; 10 int dfn[N],low[N],fa[N],dep[N],head[N]; 11 bool cut[N]; 12 struct Edge{ 13 int to,next; 14 }edge[M]; 15 void init(){ 16 tot=bridge=index=0; 17 clr(head,-1);clr(dfn,0);clr(dep,0);clr(cut,false); 18 } 19 void addedge(int u,int v){ 20 edge[tot].to=v,edge[tot].next=head[u]; 21 head[u]=tot++; 22 } 23 void tarjan(int u,int pre){ 24 dfn[u]=low[u]=++index; 25 dep[u]=dep[pre]+1; //dep代表该点深度 26 for(int i=head[u]; i!=-1; i=edge[i].next){ 27 int v=edge[i].to; 28 if(v==pre) continue; 29 if(!dfn[v]){ 30 fa[v]=u; 31 tarjan(v,u); 32 low[u]=min(low[u],low[v]); 33 if(low[v]>dfn[u]){ //桥的判定定理 34 cut[v]=1; //标记v所在边为桥 35 bridge++; 36 } 37 } 38 else 39 low[u]=min(low[u],dfn[v]); 40 } 41 } 42 void LCA(int u,int v){ //利用LCA将u->v原始路径上的所有桥全部删除 43 if(dep[u]<dep[v]) swap(u,v); 44 while(dep[u]>dep[v]){ //将u跳到与v深度相同,将路径上碰到的桥全部删除 45 if(cut[u]){ 46 bridge--; 47 cut[u]=false; 48 } 49 u=fa[u]; 50 } 51 while(u!=v){ //将u和v同时跳到他们的LCA,在路径中,凡是碰到桥,将该桥删除 52 if(cut[u]){ 53 bridge--; 54 cut[u]=false; 55 } 56 if(cut[v]){ 57 bridge--; 58 cut[v]=false; 59 } 60 u=fa[u],v=fa[v]; 61 } 62 } 63 int main(){ 64 int ncase=0; 65 while(~scanf("%d%d",&n,&m) && (n||m)){ 66 init(); 67 for(int i=1; i<=m; i++){ 68 int u,v;scanf("%d%d",&u,&v); 69 addedge(u,v);addedge(v,u); 70 } 71 tarjan(1,0); //预处理出原图中所有的桥 72 scanf("%d",&q); 73 printf("Case %d: ",++ncase); 74 while(q--){ 75 int u,v;scanf("%d%d",&u,&v); 76 LCA(u,v); //u,v之间连一条边,则改变与u->v的原始路径构成环,所以u->v原始路径上的所有桥将不复存在 77 printf("%d ",bridge); 78 }puts(""); 79 } 80 return 0; 81 }
2018-11-06