【JZOJ4201】Mike的农场

28 篇文章 0 订阅
5 篇文章 0 订阅

problem

Description

Input

Output

Sample Input

4 2 1
1 2 3 1
2 3 1 2
1 2 3
1 3 2
2 0 100 1 2

Sample Output

108

Data Constraint


analysis

  • 正解网络流,做法也是听完讲才会的

  • 既然题目要求最大收益,那么意思就是总收益亏得最少

  • 最小割

  • 首先从极源 S S 1 n n 的点各连上ai流量的边, 1 1 n的点向极汇 T T 连上bi流量的边

  • 对于规律一,从 i i j和从 j j i之间*连上流量为 k k 双向边

  • 对于规律二,如果是,新建一个节点,从源点S连向新建节点一条无穷大流量的边,从新建节点连向集合里面所有的点一条流量为 b b 的边;如果是,集合里每个点连向新建节点(流量为b),再从新建节点流向汇点 T T <script type="math/tex" id="MathJax-Element-2299">T</script>(流量无穷大

  • 最后总收益减掉最小割(最大流)就是答案


code

#include<bits/stdc++.h>
#define MAXN 1000001
#define INF 1000000007

using namespace std;

int last[MAXN],next[MAXN],tov[MAXN],odd[MAXN],cur[MAXN];
int a[MAXN],b[MAXN],depth[MAXN];
int n,m,k,S,T,tot=1,ans;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0' || '9'<ch)
    {
        if (ch=='-')f=-1;
        ch=getchar();   
    }
    while ('0'<=ch && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int min(int x,int y)
{
    return x<y?x:y; 
}

void insert(int x,int y,int z)
{
    next[++tot]=last[x];
    last[x]=tot;
    tov[tot]=y;
    odd[tot]=z;
    next[++tot]=last[y];
    last[y]=tot;
    tov[tot]=x;
    odd[tot]=0;
}

bool bfs()
{
    queue<int> que;
    while (!que.empty())que.pop();

    memset(depth,0,sizeof(depth));
    depth[S]=1;
    que.push(S);

    while (!que.empty())
    {
        int now=que.front();
        que.pop();
        for (int i=last[now];i;i=next[i])
        {
            int j=tov[i];
            if (odd[i]>0 && depth[j]==0) 
            {
                depth[j]=depth[now]+1;
                que.push(j);
            }
        }
    }
    if (depth[T]==0)return 0;
    return 1;
}

int dfs(int now,int flow) 
{
    if (now==T)return flow;
    int ans=0;
    for (int i=cur[now];i;i=next[i]) 
    {
        if (depth[tov[i]]==depth[now]+1 && odd[i]) 
        {
            int temp=dfs(tov[i],min(flow-ans,odd[i]));
            if (!temp)depth[tov[i]]=0;
            ans+=temp;
            odd[i]-=temp,odd[i^1]+=temp;
            if (ans==flow)break;
        }
    }
    return ans;
}

int dinic()
{
    int ans=0;
    while (bfs())
    {
        memcpy(cur,last,sizeof(last));
        while (int x=dfs(S,INF))ans+=x;
    }
    return ans;
}

int main()
{
    freopen("work.in","r",stdin);
    freopen("work.out","w",stdout);
    //freopen("readin.txt","r",stdin);
    n=read()+1,m=read(),k=read();
    S=0,T=n;
    for (int i=1;i<n;i++)
    {
        int x=read();
        ans+=x;
        insert(S,i,x);
    }
    for (int i=1;i<n;i++)
    {
        int x=read();
        ans+=x;
        insert(i,T,x);
    }
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read(),z=read();
        insert(x,y,z),insert(y,x,z);
    }
    for (int i=1;i<=k;i++)
    {
        int x=read(),y=read(),z=read();
        n++,ans+=z;
        (y==0)?insert(S,n,z):insert(n,T,z);
        while (x--)(y==0)?insert(n,read(),INF):insert(read(),n,INF);
    }
    printf("%d\n",ans-dinic());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值