poj 3694(求边双连通分量 缩点 暴力LCA)
来源:互联网 发布:网络空间安全 期刊 编辑:程序博客网 时间:2024/06/06 12:35
题意:给你一个无向连通图,让后给出每给q条要添加的边,输出添加每一条边之后图中还剩下多少桥
分析:向图中加入边那么就有可能是得图中的桥减小,那么我们可以先求出图中的双连通分量,那么若添加的一条边是属于某个双连通分量的那么桥的条数没有减少,如果这条边的两个顶点分别属于两个双连通子图,那么从就会使桥的数目减小,那么问题就分为两步来解决: 1、求出双连通分量后和缩点 2、加入一条边后求出桥减少的条数
第一步很好解决,这里就不赘述!
第二步:因为缩点之后新图就是一颗树,向该树中添加一条边,那么树中就会形成一条环(就形成了一个双连通分量),那么这个环上的边(当然不包含添加的那条边)就是减少的桥的条数,那么我们现在的任务就是找出加边之后形成的环中的边,那么我们可以用暴力lca(具体的见代码)
代码:
#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int N = 100005;const int E = 400005;struct node{int x,y,nxt;}edge[E],edge1[E];int e, head[N];int e1,first[N];int cnt;int Min(int a,int b){return a>b?b:a;}void addedge(int x, int y){edge[e].x=x;edge[e].y=y;edge[e].nxt=head[x];head[x]=e++;edge[e].x=y;edge[e].y=x;edge[e].nxt=head[y];head[y]=e++;}void add(int x,int y){edge1[e1].x=x;edge1[e1].y=y;edge1[e1].nxt=first[x];first[x]=e1++;}int dfn[N],low[N],index,top,st[N],blg[N];void Cutedge(int u, int fa){int v,x;low[u]=dfn[u]=index++;st[++top]=u;bool tag=false;for(int i=head[u];i!=-1;i=edge[i].nxt){ v=edge[i].y;if(v==fa&&tag==false){tag=true;continue;}//处理重边if(dfn[v]==-1){Cutedge(v,u); low[u]=Min(low[u],low[v]); if(low[v]>dfn[u]) { cnt++; do { x=st[top]; top--; blg[x]=cnt; }while(x!=v); }}else low[u]=Min(low[u],dfn[v]);}}int pre[N],father[N];void dfs(int u, int fa){//pre[u]=fa;for(int i=first[u];i!=-1;i=edge1[i].nxt){int v = edge1[i].y;if(fa==v)continue;pre[v]=u;dfs(v,u);}}int tag[N];bool vis[N];int lca(int x, int y,int c){int num,ans;if(x==y)return 0;tag[x]=c;tag[y]=c;int x1=x;int y1=y; while(1){ if(x1!=pre[x1]) {x1=pre[x1];if(tag[x1]==c){ans=x1;break;} tag[x1]=c;}if(y1!=pre[y1]){y1=pre[y1];if(tag[y1]==c){ans=y1;break;} tag[y1]=c;}} num=0; while(x!=ans) { if(vis[x]==0) {vis[x]=1;num++;} x=pre[x]; } while(y!=ans) { if(vis[y]==0) {vis[y]=1;num++;} y=pre[y]; } return num;}int main (){int n, m,k=1;int i,x,y,q;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)break;e = 0;memset(head,-1,sizeof(head));for(i=0;i<m;i++){scanf("%d%d",&x,&y);addedge(x,y);}memset(dfn,-1,sizeof(dfn));memset(low,0,sizeof(low)); index=1; top=0; cnt=0;Cutedge(1,-1);//求割边且缩点cnt++;while(top!=0){blg[st[top]]=cnt;top--;}e1=0;memset(first,-1,sizeof(first));for(i=0;i<e;i++)//缩点建图{x=blg[edge[i].x];y=blg[edge[i].y];if(x==y)continue;add(x,y);}/*for(i=1;i<=cnt;i++)for(int j=first[i];j!=-1;j=edge1[j].nxt)printf("%d %d \n",i,edge1[j].y);*/dfs(1,1);//for(i=1;i<=cnt;i++)//printf("%d ",pre[i]);//cout << endl;cnt--;scanf("%d",&q);printf("Case %d:\n",k++);memset(vis,0,sizeof(vis));memset(tag,0,sizeof(tag));for(i=1;i<=q;i++){scanf("%d%d",&x,&y);x=blg[x]; y=blg[y];//cout << x<<" " << y << endl;int num=lca(x,y,i); printf("%d\n",cnt-num); cnt-=num; }printf("\n");}return 0;}
- poj 3694(求边双连通分量 缩点 暴力LCA)
- 【边双连通分量 && LCA】POJ
- poj3694Networks(边双连通分量+缩点+LCA)
- POJ 3694 双连通分量 割边 LCA
- poj 3694 Network 边双连通分量+LCA
- poj 3177 双连通分量+缩点
- 求点双连通分量
- 图论-桥/割点/双连通分量/缩点/LCA
- POJ 3177 Redundant Paths(边双连通分量+缩点)
- poj 3177 Redundant Paths 边双连通分量+缩点
- POJ 3177 Redundant Paths 边双连通分量+缩点
- POJ 3177 Redundant Paths(边双连通分量+缩点)
- POJ-3352 Road Construction(边双连通分量+缩点)
- POJ 3177 Redundant Paths(边双连通分量+缩点)
- POJ 3177 Redundant Paths(边双连通分量+缩点)
- POJ 3352 双连通缩点以及求桥和边双连通分量
- hdu 2460(tarjan求边双连通分量+LCA)
- POJ 3694 Network 边双连通分量
- Xcode 中的GDB的命令。
- Commit、Rollback
- 利用栈实现的后缀形式的算术表达式的求值的c++程序
- 转,展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告
- OVRDBF命令
- poj 3694(求边双连通分量 缩点 暴力LCA)
- jQuery获取Select选中的Text和Value(jquery学习备忘录)
- Eclipse出现 "Project facet Java 6.0 is not supported” 解决办法
- EGL简介
- 编程之美--BYTE二进制数中1的个数
- Android Layout标签之-viewStub,requestFocus,merge,include
- 第三章:Creating Applications and activities-(一)什么组成了一个Android应用
- Could not find the main class.progrm will exit
- Learning English Every Day_September