来自NOI2006,这玩意儿可能是历史上第一道网络流吧。
记住最大权闭合子图的建图方法。还要记住网络流的边数和点数绝不能轻易定!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#define maxv 55500
#define maxe 1000005
#define inf 0x7fffffff
using namespace std;
struct edge
{
int v,f,nxt;
}e[maxe];
int nume=1,n,m,x,y,z;
int g[maxv],s=0,t,sum=0,maxcut=0,dis[maxv];
inline void addedge(int u,int v,int f)
{
e[++nume].v=v;
e[nume].f=f;
e[nume].nxt=g[u];
g[u]=nume;
e[++nume].v=u;
e[nume].f=0;
e[nume].nxt=g[v];
g[v]=nume;
}
bool bfs()
{
queue <int> q;
memset(dis,-1,sizeof(dis));
q.push(s);
dis[s]=0;
while (!q.empty())
{
int head=q.front();
q.pop();
for (int i=g[head];i;i=e[i].nxt)
{
if ((e[i].f) && (dis[e[i].v]==-1))
{
q.push(e[i].v);
dis[e[i].v]=dis[head]+1;
}
}
}
if (dis[t]==-1) return false;
return true;
}
int dinic(int x,int low)
{
if (x==t)
return low;
else
{
int ret=0;
for (int i=g[x];low && i;i=e[i].nxt)
{
if (e[i].f && dis[e[i].v]==dis[x]+1)
{
int dd=dinic(e[i].v,min(e[i].f,low));
e[i].f=e[i].f-dd;
e[i^1].f=e[i^1].f+dd;
low=low-dd;
ret=ret+dd;
}
}
if (ret==0) dis[x]=-1;
return ret;
}
}
int main()
{
memset(g,0,sizeof(g));
scanf("%d%d",&n,&m);
t=n+m+1;
for (register int i=1;i<=n;i++)
{
scanf("%d",&x);
addedge(m+i,t,x);
}
for (register int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
sum=sum+z;
addedge(s,i,z);
addedge(i,m+x,inf);
addedge(i,m+y,inf);
}
while (bfs()==true)
maxcut=maxcut+dinic(s,inf);
printf("%d\n",sum-maxcut);
return 0;
}