POJ 2914 Minimum Cut
题意:果的求无向图最小割。n个点,m条边表示图,让输出最小割有几条边。
套了前几天学的Store Wagner模板,加了注释,O(n^3)不算很快但通过无压力= =
#include<cstdio>
#include<fstream>
#include<cstring>
#define MAXV 600
using namespace std;
const int inf=1<<29;
int m,n,res,g[MAXV][MAXV];
void Mincut(int n)
{
int link[MAXV],d[MAXV]; //link作合并后的指针用,d为距离
bool vis[MAXV]; //vis访问标记
int i,pre,j,k;
for(i=0;i<n;i++) link[i]=i; //指针初始化
while(n>1){
int maxj=1;
for(i=1;i<n;i++){ //初始化到已圈集合的大小
d[link[i]]=g[link[0]][link[i]]; //先把顶点0加入集合
if(d[link[i]]>d[link[maxj]]) maxj=i; //寻找最远点
}
pre=0;
memset(vis,0,sizeof(vis));
vis[link[0]]=true;
for(i=1;i<n;i++){
if(i==n-1){ //只剩下最后一个点没加入集合,更新最小割
res=min(res,d[link[maxj]]);
for(k=0;k<n;k++) //合并最后一个节点和推出它的集合中的点
g[link[k]][link[pre]]=(g[link[pre]][link[k]]+=g[link[k]][link[maxj]]);
link[maxj]=link[--n]; //缩点后的图
}
vis[link[maxj]]=true;
pre=maxj;
maxj=-1;
for(j=1;j<n;j++)
if(!vis[link[j]]){
d[link[j]]+=g[link[pre]][link[j]]; //将上次求的maxj加入集合,合并与它相邻的边到割集
if(maxj==-1 || d[link[maxj]]<d[link[j]]) //裸的prim
maxj=j;
}
}
}
return ;
}
int main()
{
freopen("in","r",stdin);
freopen("out","w",stdout);
int u,w,v;
while(scanf("%d%d",&n,&m)!=EOF){
memset(g,0,sizeof(g));
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
g[u][v]+=w;
g[v][u]+=w;
}
res=inf;
Mincut(n);
printf("%d\n",res);
}
return 0;
}