bzoj 3438 小M的作物

3438: 小M的作物

http://www.lydsy.com/JudgeOnline/problem.php?id=3438

Time Limit: 10 Sec  Memory Limit: 256 MB
[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。
 
最大收益转化为最小损失
1、源点向作物连权值为ai的边,作物向汇点连权值为bi的边
2、将作物组合看做点,并拆为x,y,源点向x连权值为c1i的边,y向汇点连权值为c2i的边
3、对于每个作物组合中的作物k,x向k连inf边,k向y连inf边
ans= Σ ai + Σ bi + Σ c1i + Σ c2i - 最小割
 
inf边的作用:防止作物组合割了与a或b相连的边,其中的作物却割了与b或a相连的边
 
#include<cstdio>
#include<queue>
#include<algorithm>
#define N 10001
using namespace std;
const int inf=2e9+100;
int n,m,src,dec;
long long sum;
int tot=1,front[N*4],next[N*200],to[N*200],cap[N*200];
int lev[N*4],cur[N*4];
int ai[N],bi[N];
queue<int>q;
void add(int u,int v,int w)
{
    to[++tot]=v; next[tot]=front[u]; front[u]=tot; cap[tot]=w;
    to[++tot]=u; next[tot]=front[v]; front[v]=tot; cap[tot]=0;
}
bool bfs()
{
    for(int i=src;i<=dec;i++) cur[i]=front[i],lev[i]=-1;
    while(!q.empty()) q.pop();
     lev[src]=0;
    q.push(src);
    int now;
    while(!q.empty())
    {
        now=q.front(); q.pop();
        for(int i=front[now];i;i=next[i])
        {
            if(lev[to[i]]==-1&&cap[i]>0)
            {
                lev[to[i]]=lev[now]+1;
                if(to[i]==dec) return true;
                q.push(to[i]);
            }
        }
    }
    return false;
}
int dinic(int now,int flow)
{
    if(now==dec) return flow;
    int delta,rest=0;
    for(int & i=cur[now];i;i=next[i])
        if(lev[to[i]]>lev[now]&&cap[i]>0)
        {
            delta=dinic(to[i],min(flow-rest,cap[i]));
            if(delta)
            {
                cap[i]-=delta; cap[i^1]+=delta;
                rest+=delta; if(rest==flow) break;
                
            }
        }
    if(rest!=flow) lev[now]=-1;
    return rest;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&ai[i]);
    for(int i=1;i<=n;i++) scanf("%d",&bi[i]);
    scanf("%d",&m);
    src=0;dec=n+2*m+1;
    for(int i=1;i<=n;i++) { add(src,i,ai[i]); sum+=ai[i]; }
    for(int i=1;i<=n;i++) { add(i,dec,bi[i]); sum+=bi[i]; }
    int k,a,b,x;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&k,&a,&b);
        add(src,n+i,a);
        add(n+m+i,dec,b);
        sum+=a+b;
        while(k--) 
        {
            scanf("%d",&x);
            add(n+i,x,inf);
            add(x,n+m+i,inf);
        }
    }
    while(bfs()) sum-=dinic(src,inf);
    printf("%lld",sum);
}

错误:对边的数量估计错误

k可达1000,近组合中的作物连边可达1000*1000*2*2=4e6

 
posted @ 2017-04-25 09:13  TRTTG  阅读(262)  评论(0编辑  收藏  举报