标签:
题意就是至少加几条边,能够让原图没有桥。
1. 首先要找出图G的所有【边双连通分量】。
2、 把每一个【边双连通分量】都看做一个点(即【缩点】)
3、 问题再次被转化为“至少在缩点树上增加多少条树边,使得这棵树变为一个双连通图”。
首先知道一条等式:
若要使得任意一棵树,在增加若干条边后,变成一个双连通图,那么
至少增加的边数 =( 这棵树总度数为1的结点数 + 1 )/ 2
那么我们只需求缩点树中总度数为1的结点数(即叶子数)有多少就可以了。换而言之,我们只需求出所有缩点的度数,然后判断度数为1的缩点有几个,问题就解决了。
4、 求出所有缩点的度数的方法
两两枚举图G的直接连通的点,只要这两个点不在同一个【缩点】中,那么它们各自所在的【缩点】的度数都+1。注意由于图G时无向图,这样做会使得所有【缩点】的度数都是真实度数的2倍,必须除2后再判断叶子。
用了我的宇宙无敌超级大模版,1A了。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn=10000+10; //结点数量 const int Maxn=2*100000+10; //边的数量 int low[maxn]; int dfn[maxn]; int U[maxn],V[maxn];//存初始边 int flag[maxn];//判断第i条边是不是割边 int iscut[maxn];//判断i结点是不是割点,去掉之后有几个连通分量 struct Edge { int from,to,id,ans;//ans为1,表示这条边是割边 } edge[Maxn]; vector<int>G[maxn];//邻接表 int N,M;//N个结点,M条边 int tmpdfn;//时间戳 int tot; int son; int Start,End; //以下是输出点双连通分量用的 int top; struct Printf_Egde { int u,v,id; void output() {printf("(%d,%d) ",u,v);} }; Printf_Egde Stack[Maxn]; int Flag[Maxn]; int TxT[maxn];//求边双连通分量用的 //以下是缩点 vector<int>SD[maxn]; int FFLAG[maxn]; int JiHe[maxn]; int BianHao; int RuDu[maxn]; void init() { for(int i=0; i<maxn; i++) G[i].clear(); for(int i=0; i<maxn; i++) SD[i].clear(); memset(JiHe,-1,sizeof(JiHe)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(iscut,0,sizeof(iscut)); memset(Flag,0,sizeof(Flag)); memset(flag,0,sizeof(flag)); memset(TxT,0,sizeof(TxT)); memset(FFLAG,0,sizeof(FFLAG)); memset(RuDu,0,sizeof(RuDu)); low[1]=dfn[1]=1; tmpdfn=0; tot=0; son=0; top=-1; BianHao=1; } void AddEdge(int u,int v) { edge[tot].from=u; edge[tot].to=v; edge[tot].id=tot; edge[tot].ans=0; G[u].push_back(tot); tot++; edge[tot].from=v; edge[tot].to=u; edge[tot].id=tot; edge[tot].ans=0; G[v].push_back(tot); tot++; } int Tarjan(int u,int id) { tmpdfn++; int lowu=dfn[u]=tmpdfn; for(int i=0; i<G[u].size(); i++) { int B=G[u][i]; Printf_Egde t; if(!Flag[edge[B].id/2])//没有入过栈 { Flag[edge[B].id/2]=1; t.u=u; t.v=edge[B].to; t.id=edge[B].id/2; Stack[++top]=t; } if(!dfn[edge[B].to]) { int lowv=Tarjan(edge[B].to,edge[B].id); lowu=min(lowu,lowv); if(lowv>=dfn[u]) { if(u!=1) iscut[u]++; if(u==1) son++; /* //输出点双连通分量 printf("点双连通分量:"); while(1) { if(top==-1) break; Printf_Egde t1; t1=Stack[top]; t1.output(); top--; if(t1.id==t.id) break; } printf("\n"); */ //判断是不是割边 if(lowv>dfn[u]) edge[B].ans=1; } } else if(dfn[edge[B].to]) { if(edge[B].id/2==id/2) continue; lowu=min(lowu,dfn[edge[B].to]); } } low[u]=lowu; return lowu; } void Display_Cutting_edge() { for(int i=0; i<2*M; i++) if(edge[i].ans) { FFLAG[i]=1; //printf("第%d条边是割边:(%d,%d)\n",edge[i].id/2,edge[i].from,edge[i].to); } } void Display_Cutting_point() { if(son>1) iscut[1]=son-1; for(int i=Start;i<=End;i++) if(iscut[i]){} //printf("编号为%d的结点是割点,删除后有%d个连通分量\n",i,iscut[i]+1); } void Dfs(int x,int y) { int XZ=0; for(int i=0;i<G[x].size();i++) { int B=G[x][i]; if(!flag[edge[B].id/2]) { XZ=1; flag[edge[B].id/2]=1; TxT[edge[B].to]=1; // printf("(%d,%d) ",edge[B].from,edge[B].to); if(JiHe[edge[B].from]==-1&&JiHe[edge[B].to]==-1) { JiHe[edge[B].from]=BianHao; JiHe[edge[B].to]=BianHao; BianHao++; } else if(JiHe[edge[B].from]!=-1) JiHe[edge[B].to]=JiHe[edge[B].from]; else if(JiHe[edge[B].to]!=-1) JiHe[edge[B].from]=JiHe[edge[B].to]; Dfs(edge[B].to,y+1); } } if(!XZ&&!y) { //printf("(%d) ",x); if(JiHe[x]==-1) { JiHe[x]=BianHao; BianHao++; } } } void Slove() { //把桥都标为1 for(int i=0; i<2*M; i++) if(edge[i].ans) flag[edge[i].id/2]=1; for(int i=Start;i<=End;i++) { if(!TxT[i]) { TxT[i]=1; // printf("边双连通分量:"); Dfs(i,0); // printf("\n"); } } } int main() { while(~scanf("%d%d",&N,&M)){ init(); for(int i=0; i<M; i++) { scanf("%d%d",&U[i],&V[i]); AddEdge(U[i],V[i]); } //设置结点编号的起点和终点 Start=1; End=N; Tarjan(1,-1); //割点的输出 Display_Cutting_point(); //割边的输出 Display_Cutting_edge(); //点双连通分量在Tarjan过程中已经输出了 //求边双连通分量,并输出 Slove(); for(int i=0;i<2*M;i++) { if(JiHe[edge[i].from]!=JiHe[edge[i].to]) { RuDu[JiHe[edge[i].from]]++; RuDu[JiHe[edge[i].to]]++; } } int AAns=0; for(int i=1;i<BianHao;i++) { RuDu[i]=RuDu[i]/2; if(RuDu[i]==1) AAns++; } printf("%d\n",(AAns+1)/2);} return 0; }
标签:
原文地址:http://www.cnblogs.com/zufezzt/p/4722538.html