題目鏈接: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 }