题目链接:http://poj.org/problem?id=1966
思路:从网上找了一下大牛对于这类问题的总结:图的连通度问题是指:在图中删去部分元素(点或边),使得图中指定的两个点s和t不连通 (不存在从s到t的路径),求至少要删去几个元素。
图的连通度分为点连通度和边连通度:
(1)点连通度:只许删点,求至少要删掉几个点(当然,s和t不能删去,这里保证原图中至少有三个点);
(2)边连通度:只许删边,求至少要删掉几条边。
并且,有向图和无向图的连通度求法不同,因此还要分开考虑(对于混合图,只需将其中所有的无向边按照
无向图的办法处理、有向边按照有向图的办法处理即可)。
【1】有向图的边连通度:
这个其实就是最小割问题。以s为源点,t为汇点建立网络,原图中的每条边在网络中仍存在,容量为1,求该网络的最小割(也就是最大流)的值即为原图的边连通度。
【2】有向图的点连通度:
需要拆点。建立一个网络,原图中的每个点i在网络中拆成i'与i'',有一条边<i', i''>,容量为1 (<s', s''>和<t', t''>例外,容量为正无穷)。原图中的每条边<i, j>在网络中为边<i'', j'>,
容量为正无穷。以s'为源点、t''为汇点求最大流,最大流的值即为原图的点连通度。
说明:最大流对应的是最小割。显然,容量为正无穷的边不可能通过最小割,也就是原图中的边和s、t两个点不能删去;若边<i, i''>通过最小割,则表示将原图中的点i删去。
【3】无向图的边连通度:
将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【1】)处理;
【4】无向图的点连通度:
将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【2】)处理。
于是对于本题我们可以枚举源点和汇点求解。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define MAXN 111 8 #define inf 1<<30 9 10 struct Edge{ 11 int v,cap,next; 12 }edge[MAXN*MAXN]; 13 14 int n,m,NE,NV; 15 int head[MAXN]; 16 17 void Insert(int u,int v,int cap) 18 { 19 edge[NE].v=v; 20 edge[NE].cap=cap; 21 edge[NE].next=head[u]; 22 head[u]=NE++; 23 24 edge[NE].v=u; 25 edge[NE].cap=0; 26 edge[NE].next=head[v]; 27 head[v]=NE++; 28 } 29 30 int level[MAXN],gap[MAXN]; 31 void bfs(int vt) 32 { 33 memset(level,-1,sizeof(level)); 34 memset(gap,0,sizeof(gap)); 35 level[vt]=0; 36 gap[level[vt]]++; 37 queue<int>que; 38 que.push(vt); 39 while(!que.empty()){ 40 int u=que.front(); 41 que.pop(); 42 for(int i=head[u];i!=-1;i=edge[i].next){ 43 int v=edge[i].v; 44 if(level[v]!=-1)continue; 45 level[v]=level[u]+1; 46 gap[level[v]]++; 47 que.push(v); 48 } 49 } 50 } 51 52 int pre[MAXN],cur[MAXN]; 53 int SAP(int vs,int vt) 54 { 55 bfs(vt); 56 memset(pre,-1,sizeof(pre)); 57 memcpy(cur,head,sizeof(head)); 58 int maxflow=0,aug=inf; 59 int u=pre[vs]=vs; 60 gap[0]=NV; 61 while(level[vs]<NV){ 62 bool flag=false; 63 for(int &i=cur[u];i!=-1;i=edge[i].next){ 64 int v=edge[i].v; 65 if(edge[i].cap>0&&level[u]==level[v]+1){ 66 flag=true; 67 pre[v]=u; 68 u=v; 69 aug=min(aug,edge[i].cap); 70 if(v==vt){ 71 maxflow+=aug; 72 for(u=pre[v];v!=vs;v=u,u=pre[u]){ 73 edge[cur[u]].cap-=aug; 74 edge[cur[u]^1].cap+=aug; 75 } 76 aug=inf; 77 } 78 break; 79 } 80 } 81 if(flag)continue; 82 int minlevel=NV; 83 for(int i=head[u];i!=-1;i=edge[i].next){ 84 int v=edge[i].v; 85 if(edge[i].cap>0&&level[v]<minlevel){ 86 minlevel=level[v]; 87 cur[u]=i; 88 } 89 } 90 if(--gap[level[u]]==0)break; 91 level[u]=minlevel+1; 92 gap[level[u]]++; 93 u=pre[u]; 94 } 95 return maxflow; 96 } 97 98 bool map[MAXN][MAXN]; 99 void Build() 100 { 101 NE=0; 102 memset(head,-1,sizeof(head)); 103 for(int i=0;i<n;i++){ 104 for(int j=0;j<n;j++){ 105 if(i==j)Insert(i,i+n,1); 106 else if(map[i][j])Insert(i+n,j,inf); 107 } 108 } 109 } 110 111 int main() 112 { 113 // freopen("1.txt","r",stdin); 114 int u,v,ans; 115 while(~scanf("%d%d",&n,&m)){ 116 NV=2*n; 117 memset(map,false,sizeof(map)); 118 while(m--){ 119 scanf(" (%d,%d)",&u,&v); 120 map[u][v]=map[v][u]=true; 121 122 } 123 ans=inf; 124 for(int vs=0;vs<n;vs++){ 125 for(int vt=vs+1;vt<n;vt++){ 126 Build(); 127 ans=min(ans,SAP(vs+n,vt)); 128 } 129 } 130 if(ans>=n)ans=n; 131 printf("%d\n",ans); 132 } 133 return 0; 134 }