OIIIIIIII

「BZOJ3438」小M的作物(最小割

3438: 小M的作物

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1891  Solved: 801
[Submit][Status][Discuss]

Description

小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子
有1个(就是可以种一棵作物)(用1...n编号),现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植
可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益
,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以
获得c2i的额外收益,所以,小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?

Input

第一行包括一个整数n
第二行包括n个整数,表示ai第三行包括n个整数,表示bi第四行包括一个整数m接下来m行,
对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,
接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。输出格式

Output

只有一行,包括一个整数,表示最大收益

Sample Input

3
4 2 1
2 3 2
1
2 3 2 1 2

Sample Output

11
样例解释A耕地种1,2,B耕地种3,收益4+2+3+2=11。
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。

题解

被洛谷大佬刷到绿了 好过分QAQ

读了题之后就在想怎么处理组合和个体之间的不相容性。一开始打算用拆点的方法限流,然后粗略算了一下 边数会爆炸QAQ

然后看了题解(=_=),fa现可以巧妙的用上最小割

把源点当作A,汇点当作B,源点往每个作物连ai,作物往B连bi。

首先对于没有组合:

割一下,留在左边的种进A,右边的种进B,那么收益就是剩下来的边权之和。

对于组合:

建一个虚点,从源点连一条c1i,再往每个受它控制的点连INF;

再建一个虚点,往汇点连一条c2i,再从每个受它控制的点连INF;

(图是毛来的)

其中黄边为对应值,蓝边为INF

以下为建图合理性的证明:

首先,INF永远割不掉。

对于左边,如果S->c已经被割掉,也就是说c变成了B的大宝贝儿,

想让c这条支流断掉,有两种选择:割左边的黄线,或者把右边的黄线和c->T一起割掉。

而如果割右边的,则不符合一开始让c加入B战队的假定,且S->c割的不明不白。

所以反证得知此时左边的黄线肯定会断。

同理可证,如果c->T被割掉,X'到T也会断。

∴证得割掉组合内任意点,这个组合的群体优惠也会断掉。

而如果某个组合的左边黄线存在,

那么割它下面的绿线都是白割,反正过的去。

对于右边同理。

∴如果某个组合优惠被得到了,那么它的所有儿砸都会留下。易知此时流量既得到了组合优惠,也收到了单个收益。

所以这样建图是ojbk的。

建了图然后跑个dinic算最小割,再用总边权减一下就好了。

撒花~

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int INF=2*1e9+1;
struct emm{
    int e,f,v;
}a[2000007];
int h[50007];
int tot=1;
int s,t;
void con(int x,int y,int w)
{
    a[++tot].f=h[x];
    h[x]=tot;
    a[tot].e=y;
    a[tot].v=w;
    a[++tot].f=h[y];
    h[y]=tot;
    a[tot].e=x;
    return;
}
queue<int>q;
int d[50007];
inline bool bfs()
{
    memset(d,0,sizeof(d));
    d[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=h[x];i;i=a[i].f)
        if(!d[a[i].e]&&a[i].v)
        {
            d[a[i].e]=d[x]+1;
            q.push(a[i].e);
        }
    }
    return d[t];
}
int dfs(int x,int al)
{
    if(x==t||!al)return al;
    int fl=0;
    for(int i=h[x];i;i=a[i].f)
    if(d[a[i].e]==d[x]+1&&a[i].v)
    {
        int f=dfs(a[i].e,min(a[i].v,al));
        if(f)
        {
            fl+=f;
            al-=f;
            a[i].v-=f;
            a[i^1].v+=f;
            if(!al)break;
        }
    }
    if(!fl)d[x]=-1;
    return fl;
}
int main()
{
    //freopen("a.in","r",stdin);
    int n;
    scanf("%d",&n);
    s=0,t=50001;
    long long all=0;
    for(int i=1;i<=n;++i)
    {
        int x;
        scanf("%d",&x);
        all+=x;
        con(s,i,x);
    }
    for(int i=1;i<=n;++i)
    {
        int x;
        scanf("%d",&x);
        all+=x;
        con(i,t,x);
    }
    int m;
    scanf("%d",&m);
    int nod=n;
    for(int i=1;i<=m;++i)
    {
        int ki,c1,c2;
        scanf("%d%d%d",&ki,&c1,&c2);
        nod++;
        con(s,nod,c1);
        con(nod+1,t,c2);
        all+=c1;
        all+=c2;
        for(int j=1;j<=ki;++j)
        {
            int x;
            scanf("%d",&x);
            con(nod,x,INF);
            con(x,nod+1,INF);
        }
        nod++;
    }
    long long ans=0;
    while(bfs()){ans+=dfs(s,INF);}
    cout<<all-ans;
    return 0;
}

 

posted @ 2018-08-25 19:47  qwertaya  阅读(292)  评论(0编辑  收藏  举报
MDZX
Changsha
Fulan