Time Limit: 3 Sec Memory Limit: 512 MB
Submit: 172 Solved: 81
[Submit][Status][Discuss]
Description
有一个N(<=500)的无向图,求将这个图断成两个联通块需要删除的边的边权和最小值。
Input
两个数n,m,然后m个数每行三个数a,b,c,表示a和b这两个点的连系为c (不会重复出现一对a和b,无序)
Output
一个数表示最小的联系度和(即无向图最小割)
Sample Input
3 3
1 2 1
2 3 1
3 1 2
Sample Output
2
HINT
m<=10000
Source
这篇博文之前写过,在POJ分类里,POJ从0开始,BZOJ从1开始
#include<cstdio>
#include<climits>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define N 505
#define INF INT_MAX/3*2
struct Min_Cut{
struct Dist{
int s,d;
};
int mp[N][N];bool use[N];
int n,m,ans,S,T;
int in(){
int x=0;char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
void init(){
memset(mp,0,sizeof(mp));memset(use,0,sizeof(use));
int x,y,z;ans=INF;
while(m--){
x=in()-1,y=in()-1,z=in();
mp[x][y]+=z;mp[y][x]+=z;
}
return;
}
int MinCut(int &s,int &t){
bool vis[N];int w[N];
memset(vis,0,sizeof(vis));memset(w,0,sizeof(w));
int tmpj=N;
for(int i=0;i<n;i++){
int max=-INF;
for(int j=0;j<n;j++){
if(!vis[j]&&!use[j]&&max<w[j]){
max=w[j];
tmpj=j;
}
}
if(t==tmpj){return w[t];}
vis[tmpj]=1;
s=t,t=tmpj;
for(int j=0;j<n;j++){
if(!vis[j]&&!use[j])
w[j]+=mp[t][j];
}
}
return w[t];
}
void solve(){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<n;i++){
S=T=-1;ans=min(ans,MinCut(S,T));use[T]=true;
for(int j=0;j<n;j++){
mp[S][j]+=mp[T][j];
mp[j][S]+=mp[j][T];
}
}
printf("%d\n",ans);
return;
}
}s;
int main(){
s.solve();
return 0;
}