真的是日了DOG了 发现Mincut返回错东西了
关于最小割的话我们可以任取一个点作为S 然后枚举T进行最大流
O(n4)
时间复杂度显然是那么我们跑不过去
这了我们需要的是一个叫Stoer wagner的算法 时间复杂度为
O(n3)
算法的整体思想是不停的将图缩点并在缩点过程中更新答案
每次扩展一个当前联通度最大的节点并更新其他未扩展节点的联通度直到无节点可以继续扩展
这时候我们有一个扩展节点的顺序 将最后扩展的节点的联通度用来更新答案 取最后扩展的两个点缩点 (这里与倒数第二个节点缩点是为了让可更新更小)
每一次我们都回找到一个点 这个点代表了一个点集 而这个点的联通度就是这个点集 于这个点集的补集的割
具体实现看代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<queue>
using namespace std;
char c;
inline void read(int &a)
{
a=0;do c=getchar();while(c<'0'||c>'9');
while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}
int M[501][501];
int n;
struct Res
{
int len,u,v;
inline friend bool operator<(Res a,Res b){return a.len<b.len;}
};
int size[501],f[501];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void Union(int u,int v){if(size[u]<size[v])swap(u,v);f[u]=f[v];if(size[u]==size[v])size[u]++;}
int Du[501];
bool use[501];
int Mincut()
{
int res=1<<29,tp;
for(int i=1;i<n;i++)
{
for(int j=1;j<=n;j++)use[j]=false,f[j]=j,size[j]=1,Du[j]=0;
Res R;tp=0;
int u=1,v=1;
for(int j=1;j<=n;j++)
Du[j]+=M[u][j];
use[1]=true;
for(int j=1;j+i<=n;j++)
{
u=v;
v=0;
for(int k=1;k<=n;k++)
if(use[k]==false&&Du[k]>Du[v])v=k;
use[v]=true;
for(int k=1;k<=n;k++)
Du[k]+=M[v][k];
}
res=min(res,Du[v]);
if(u>v)swap(u,v);
for(int i=1;i<=n;i++)
if(M[i][v])
M[u][i]=M[i][u]+=M[i][v],M[v][i]=M[i][v]=0;
M[u][v]=0,M[u][u]=0;
}
return res;
}
int main()
{
int m;
read(n),read(m);
for(int i=1;i<=m;i++)
{
int j,k;read(j),read(k),read(M[j][k]),M[k][j]=M[j][k];
}
int ans=Mincut();
printf("%d\n",ans);
}