轉自:夜晚的蟲子 http://blog.sina.com.cn/s/blog_700906660100v7vb.html
割:在一個圖G(V,E)中V是點集,E是邊集。在E中去掉一個邊集C使得G(V,E-C)不連通,C就是圖G(V,E)的一個割;
最小割:在G(V,E)的所有割中,邊權總和最小的割就是最小割。
求G的任意s-t最小割Min-C(s,t):
設s,t是途中的兩個點且邊(s,t)∈E(即s,t之間存在一條邊)。如果G的最小割Cut把G分成M,N兩個點集
①:如果s∈M,t∈N則Min-C(s,t)= Cut(不討論)
②:如果s,t∈M(或者s,t∈N)則Min-C(s,t)<= Cut
我們來定義一個Contract(a,b)操作,即把a,b兩個點合併,表示爲刪除節點b,把b的節點信息添加到a上
如下圖是做了Contract(5,6)
對於所點v有w(v,5)+=w(v,6)
求s-t最小割的方法
定義w(A,x) = ∑w(v[i],x),v[i]∈A
定義Ax爲在x前加入A的所有點的集合(不包括x)
1.令集合A={a},a爲V中任意點
2.選取V-A中的w(A,x)最大的點x加入集合
3.若|A|=|V|,結束,否則更新w(A,x),轉到2
令倒數第二個加入A的點爲s,最後一個加入A的點爲t,則s-t最小割爲w(At,t)
以Poj (pku) 2914 Minimum Cut
的第三個case爲例,圖爲
G(V,E)
我們設法維護這樣的一個w[],初始化爲0;
我們把V-A中的點中w[i]最大的點找出來加入A集合;
V-A直到爲空
w[]的情況如下
w[i] |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
初始值 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
A=A∪{0} |
--- |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
A=A∪{1} |
|
--- |
2 |
2 |
1 |
0 |
0 |
0 |
A=A∪{2} |
|
|
--- |
3 |
1 |
0 |
0 |
0 |
A=A∪{3} |
|
|
|
--- |
1 |
0 |
0 |
1 |
A=A∪{4} |
|
|
|
|
--- |
1 |
1 |
2 |
A=A∪{7} |
|
|
|
|
|
2 |
2 |
--- |
A=A∪{5} |
|
|
|
|
|
--- |
3 |
|
A=A∪{6} |
|
|
|
|
|
|
--- |
|
每次w[i]+=∑(i,a)的權值a∈A
記錄最後加入A的節點爲t=6,倒數第二個加入A的爲s=5,則s-t的最小割就爲w[s],在圖中體現出來的意思就是5-6的最小割爲w[s]=3
然後我們做Contract(s,t)操作,得到下圖
G(V’,E’)
重複上述操作
w[i] |
0 |
1 |
2 |
3 |
4 |
5 |
7 |
初始值 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
A=A∪{0} |
--- |
1 |
1 |
1 |
1 |
0 |
0 |
A=A∪{1} |
|
--- |
2 |
2 |
1 |
0 |
0 |
A=A∪{2} |
|
|
--- |
3 |
1 |
0 |
0 |
A=A∪{3} |
|
|
|
--- |
1 |
0 |
1 |
A=A∪{4} |
|
|
|
|
--- |
2 |
2 |
A=A∪{5} |
|
|
|
|
|
--- |
4 |
A=A∪{7} |
|
|
|
|
|
|
--- |
s=5,t=7
Contract(s,t)得到
w[i] |
0 |
1 |
2 |
3 |
4 |
5 |
初始值 |
0 |
0 |
0 |
0 |
0 |
0 |
A=A∪{0} |
--- |
1 |
1 |
1 |
1 |
0 |
A=A∪{1} |
|
--- |
2 |
2 |
1 |
0 |
A=A∪{2} |
|
|
--- |
3 |
1 |
0 |
A=A∪{3} |
|
|
|
--- |
1 |
1 |
A=A∪{4} |
|
|
|
|
--- |
4 |
A=A∪{5} |
|
|
|
|
|
--- |
s=4,t=5
Contract(s,t)得到
w[i] |
0 |
1 |
2 |
3 |
4 |
初始值 |
0 |
0 |
0 |
0 |
0 |
A=A∪{0} |
--- |
1 |
1 |
1 |
1 |
A=A∪{1} |
|
--- |
2 |
2 |
1 |
A=A∪{2} |
|
|
--- |
3 |
1 |
A=A∪{3} |
|
|
|
--- |
2 |
A=A∪{4} |
|
|
|
|
--- |
s=3,t=4
AC代碼:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#define INT_MAX 0x3f3f3f3f
using namespace std;
int mp[502][502];
int N,M;
bool combine[502];
int minC=INT_MAX;
void search(int &s,int &t){
bool vis[502];
int w[502];
memset(vis,0,sizeof(vis));
memset(w,0,sizeof(w));
int tmpj=1000;
for(int i=0;i<N;i++){
int max=-INT_MAX;
for(int j=0;j<N;j++){
if(!vis[j]&&!combine[j]&&max<w[j]){
max=w[j];
tmpj=j;
}
}
if(t==tmpj){minC=w[t];return;}
vis[tmpj]=1;
s=t,t=tmpj;
for(int j=0;j<N;j++){
if(!vis[j]&&!combine[j])
w[j]+=mp[t][j];
}
}
minC=w[t];
}
int mincut(){
int ans=INT_MAX;
int s,t;
memset(combine,0,sizeof(combine));
for(int i=0;i<N-1;i++){
s=t=-1;
search(s,t);
combine[t]=true;
ans=ans>minC?minC:ans;
for(int j=0;j<N;j++){
mp[s][j]+=mp[t][j];
mp[j][s]+=mp[j][t];
}
}
return ans;
}
int main(){
//freopen("in.txt","r",stdin);
while(cin>>N>>M){
memset(mp,0,sizeof(mp));
int u,v,w;
while(M--){
scanf("%d %d %d",&u,&v,&w);
mp[u][v]+=w;
mp[v][u]+=w;
}
cout<<mincut()<<endl;
}
return 0;
}