最大获利

链接:https://www.luogu.org/problemnew/show/P4174

题解:

最大权闭合子图裸题

常规连边,砍掉一条边代表不干这件事情

在这题中的体现就是,抉择和顾客间连INF,代表不会被砍

顾客和t连收益,砍了说明没收益

源和花费连边,砍了说明没花费

注意一下数组的大小就可以了,建了8倍的边

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxn 400010
#define INF 1e9
int n,m,c,dd,e,ans,s,t,d[maxn],head[maxn],l,b[maxn];
bool vis[maxn];
struct re{
    int a,b,c,flow;
}a[maxn];
void arr(int x,int y,int z,int flow)
{
    a[++l].a=head[x];
    a[l].b=y;
    a[l].c=z;
    a[l].flow=flow;
    head[x]=l;
}
bool bfs(){
    memset(vis,0,sizeof(vis));
    queue<int> q;
    q.push(s);
    d[s]=0; vis[s]=1;
    while (!q.empty())
    {
        int x=q.front();q.pop();
        int u=head[x];
        while (u)
        {
            int v=a[u].b;
            if (!vis[v]&&a[u].c>a[u].flow)
            {
                vis[v]=1;
                d[v]=d[x]+1;
                q.push(v);
            }
            u=a[u].a;
        }
    }
    return(vis[t]);
}
int dfs(int x,int y)
{
    if (x==t||y==0) return y;
    int flow=0,f,tmp;
    int u=head[x];
    while (u)
    {
        int v=a[u].b;
        if (d[x]+1==d[v]&&(f=dfs(v,min(y,a[u].c-a[u].flow)))>0)
        {
            a[u].flow+=f;
            if (u%2) tmp=u+1; else tmp=u-1;
            a[tmp].flow-=f;
            flow+=f; 
            y-=f;
            if (y==0) break;
        }
        u=a[u].a;
    }
    return(flow);
}
int maxflow()
{
    int flow=0;
    while (bfs())
    {
        flow+=dfs(s,INF);
    }
    return(flow);
}
int main()
{
    freopen("noip.in","r",stdin);
    freopen("noip.out","w",stdout);
    cin>>n>>m; s=0; t=n+m+1;
    for (int i=1;i<=n;i++)
    { 
      cin>>b[i];
      arr(i+m,t,b[i],0); arr(t,i+m,0,0);
    }
    for (int i=1;i<=m;i++)
    {
        cin>>c>>dd>>e;
        arr(i,c+m,INF,0); arr(c+m,i,0,0);
        arr(i,dd+m,INF,0); arr(dd+m,i,0,0);
        arr(0,i,e,0); arr(i,0,0,0);
        ans+=e;
    }
    ans-=maxflow();
    cout<<ans;
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/8438903.html