bzoj2163

题解:

拆点网络流

然后用总和-最大流

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N=100005;
int ne[N],tot,fi[N],zz[N],z,sl[N],q[N],T,n,m,sum,F[N],dis[N],x,y,cas,ans,f[N];
void jb(int x,int y,int z)
{
    ne[tot]=fi[x];
    fi[x]=tot;
    zz[tot]=y;
    sl[tot++]=z;
    ne[tot]=fi[y];
    fi[y]=tot;
    zz[tot]=x;
    sl[tot++]=0;
}
int bfs()
{
    memset(dis,0xff,sizeof dis);
    dis[1]=0;
    int l=0,r=1;
    q[1]=1;
    while (l<r)
     {
         int j=q[++l];
         for (int i=fi[j];i!=-1;i=ne[i])
          if (dis[zz[i]]<0&&sl[i]>0)
           {
               dis[zz[i]]=dis[j]+1;
               q[++r]=zz[i];
           }
     }
    if (dis[2*n+2]>0)return 1;
    return 0; 
}
int find(int x,int low)
{
    int b=0;
    if (x==2*n+2)return low;
    for (int i=fi[x];i!=-1;i=ne[i])
     if (sl[i]>0&&dis[zz[i]]==dis[x]+1&&(b=find(zz[i],min(low,sl[i]))))
      {
          sl[i]-=b;
          sl[i^1]+=b;
          return b;
      }
    return 0;  
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(fi,-1,sizeof fi);
    for (int i=1;i<=n;i++)
     {
        scanf("%d",&F[i]);
        jb(1,i+1,F[i]);
        jb(i+1+n,n*2+2,F[i]);
        sum+=F[i];
     }
    while (m--)
     {
        scanf("%d%d%d",&x,&y,&z);
        jb(x+1,1+n+y,z);
     } 
    int t; 
    while (bfs())
     while (t=find(1,1e9))ans+=t;
    printf("%d
",sum-ans);
}
原文地址:https://www.cnblogs.com/xuanyiming/p/8427834.html