题意:求无向图全局最小割。点的数量有点大,使用优先队列优化(但貌似在稠密图中,还没有n^3快)。
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<deque>
#include<vector>
#include<functional>
using namespace std;
#define LL long long
#define mm(a,b) memset(a,b,sizeof(a))
const double eps=1.0e-6;
const double PI=acos(-1.0);
template<typename T>T gcd(T a,T b){return b==0?a:gcd(b,a%b);}
template<typename T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<typename T>T _abs(T a){return a>0?a:-a;}
typedef pair<int,int> P;
const int maxn=3010;
const int inf=1<<30;
struct edge
{
int to,w,next,v;
}e[maxn*maxn];
int n,m,cnt,head[maxn];
int mp[maxn][maxn],fa[maxn];
void add(int x,int y,int z)
{
e[cnt].to=y;
e[cnt].w=z;
e[cnt].v=0;
e[cnt].next=head[x];
head[x]=cnt++;
e[cnt].to=x;
e[cnt].w=z;
e[cnt].v=0;
e[cnt].next=head[y];
head[y]=cnt++;
}
int find(int x)
{
return fa[x]=fa[x]==x?x:find(fa[x]);
}
bool lt()//并查集判定图是否连通
{
for(int i=1;i<=n;i++)
{
int fx=find(i);
if(fx!=fa[1])
return false;
}
return true;
}
int S,T;//最后并入集合的两点
int w[maxn];//点的权值
bool vis[maxn];//点是否在集合中
bool st[maxn];//点是否已经合并
int solve(int num)//找S-T的最小割
{
int mincut=0;
mm(w,0);
mm(vis,0);
priority_queue<P> q;
for(int i=head[1];~i;i=e[i].next)
if(!st[e[i].to]&&!vis[e[i].to])
{
w[e[i].to]+=e[i].w;
q.push(P(w[e[i].to],e[i].to));
}
vis[1]=1;
for(int i=1;i<num;i++)
{
P t;
while(q.size())
{
t=q.top();
q.pop();
if(!st[t.second]&&!vis[t.second])
break;
}
if(t.second==T)//图不连通
break;
vis[t.second]=1;//找到还没有合并的权值最大的点并入集合
mincut=w[t.second];
S=T,T=t.second;
for(int j=head[t.second];~j;j=e[j].next)
if(!st[e[j].to]&&!vis[e[j].to])
{
w[e[j].to]+=e[j].w;
q.push(P(w[e[j].to],e[j].to));
}
}
return mincut;
}
int stoer_wagner()
{
S=T=0;
int ans=inf;
mm(st,0);
queue<int> q;
for(int i=1;i<n;i++)
{
ans=min(ans,solve(n-i+1));
if(ans==0)
return 0;
st[T]=1;
//S与T合并
for(int j=head[S];~j;j=e[j].next)
for(int k=head[T];~k;k=e[k].next)
if(e[j].to==e[k].to)
{
e[j].w+=e[k].w;
e[j^1].w=e[j].w;
e[k].v=1;
}
for(int k=head[T];~k;k=e[k].next)
if(!e[k].v&&e[k].to!=S)
{
q.push(k);
e[k^1].to=S;
}
while(q.size())
{
int t=q.front();
q.pop();
e[t].next=head[S];
head[S]=t;
}
}
return ans;
}
int main()
{
int x,y,z;
while(~scanf("%d%d",&n,&m))
{
cnt=0;
mm(mp,0);
mm(head,-1);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
mp[x][y]=mp[y][x]=mp[x][y]+z;
int fx=find(x),fy=find(y);
fa[fx]=fy;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(mp[i][j])
add(i,j,mp[i][j]);
if(!lt())
puts("0");
else
printf("%d\n",stoer_wagner());
}
return 0;
}