这道题的意思是给n个中转站以及它们的花费,建成某几对中转站会获得一些收益,求净利润的最大值。首先用网络流做的题一般都可以分成两个集合,比如这道题我们可以将中转站分成选和不选两个集合,我们将获得收益的两个中转站与一个新节点连一条流量为正无穷的边,再将新节点与汇点连一条流量为收益的边,我们将每一个中转站与源点连一条流量为花费的边。然后我们默认所有收益都得到,然后再在图中找到最小割,用所有收益减去最小割就是答案。为什么呢?首先我们连的流量为正无穷的边一定不会出现在最小割中,这些边只是保证图的连通性的,这样我们割的边一定是与源点相连或是与汇点相连的边,割掉与源点相连的边说明我们选这个点,答案要减去它的花费,割掉与汇点相连的边说明我们不选这对中转站,那我们就要减去它的收益,由于是最小割,所以保证了答案是最大的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxm 1000005
#define maxn 60005
#define INF 1000000000
int last[maxn],pre[maxm],other[maxm],cap[maxm];
int n,m,l,S,T,d[maxn],q[maxm+5],sum,ans;
void connect(int x,int y,int z)
{
pre[l]=last[x];
last[x]=l;
other[l]=y;
cap[l]=z;
l++;
swap(x,y);
pre[l]=last[x];
last[x]=l;
other[l]=y;
cap[l]=0;
l++;
}
bool bfs(void)
{
memset(d,0,sizeof d);
int h=0,t=1;
q[1]=S;d[S]=1;
while (h!=t)
{
h=h%maxm+1;
int u=q[h];
for (int p=last[u];p!=-1;p=pre[p])
{
int v=other[p];
if (d[v]||cap[p]==0) continue;
d[v]=d[u]+1;
if (v==T) return 1;
t=t%maxm+1;
q[t]=v;
}
}
return 0;
}
int dinic(int u,int flow)
{
int rest=flow;
if (u==T) return flow;
for (int p=last[u];p!=-1;p=pre[p])
{
int v=other[p];
if (rest>0&&cap[p]>0&&d[v]==d[u]+1)
{
int temp=dinic(v,min(rest,cap[p]));
rest-=temp;
cap[p]-=temp;
cap[p^1]+=temp;
}
}
return flow-rest;
}
int main()
{
scanf("%d%d",&n,&m);
S=0;T=n+m+1;
memset(last,-1,sizeof last);
for (int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
connect(S,i,a);
}
for (int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
connect(a,n+i,INF);
connect(b,n+i,INF);
connect(n+i,T,c);
sum+=c;
}
while (bfs())
ans+=dinic(S,INF);
printf("%d\n",sum-ans);
return 0;
}