P1361 小M的作物

题目描述

小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号)。

现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益。

小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?

输入输出格式

输入格式:

 

第一行包括一个整数n

第二行包括n个整数,表示ai第三行包括n个整数,表示bi第四行包括一个整数m接下来m行,

对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,

接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
3
4 2 1
2 3 2
1
2 3 2 1 2
输出样例#1: 复制
11

说明

样例解释

A耕地种1,2,B耕地种3,收益4+2+3+2=11。

数据范围与约定

1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。

 

//我还真以为这是个最大流板子。。。

//画图的时候发现,如果直接S向作物连INF的边,作物向A、B连各自收益的边,然后A、B向T连边的话,
//。。。那肯定不对啊,因为一个作物可以有两种互不干扰的选择了。。
//那我们就让他们互相干扰,只能往一块地上种,怎么办呢?
//S向农作物连种在A的收益,农作物向T连重在B的收益,这样就每种作物只能选一个了
//...但是这样出来是选的最小的。。。  话说网络流就是跑最小的。。。
//那我们一减就是最大的了。。
//。那这不是最小割吗。
//组合的情况怎么办呢?
//新设两个点x和y
//让S向x连在A种的边,边权为这个组合在A种获得的收益,x向组合内的作物连inf的边, 
//组合内作物向y连inf的边,y向T连在B种的边,边权为在B种获得的收益
//这样跑出来的最大流就是能获得的最小收益
//总收益减一下就是最大收益了 

//好吧我无言以对,上午一直WA第二个点,气得我差点就特判A那个点了
//但是我没猜出那个点是啥来。。。
//好吧也不知道错误在哪
//下午来了,被班主任踢了两脚,敲另一个题的时候突然想起:
//我要初始化num_edge=1 !!!!!!
//不初始化的话,i^1就不是反向边了    刚学网络流发现要写num_edge=1的时候就预料到了肯定会翻车的 果不其然 
//上午把这个题改成最大流板子跑样例,发现打错了
//改过来,过样例了,但是我没写num_edge=1,他仍然是错的。。。
//样例都是骗小孩的,我应该提交一次的

//所以,不要把时间卡在一道题上,上午的sb错误,放过它去,下午以来说不定就知道了
//(当然可能需要班主任触发) 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

const int N=1e4+5;
const int M=4e6+5;
const int INF=0x7fffffff;

int n,m,S,T,V;
int head[N],front[N],num_edge;
struct Edge
{
    int v,flow,nxt;
}edge[M];

inline int read()
{
    char c=getchar();int num=0,f=1;
    for(;!isdigit(c);c=getchar())
        f=c=='-'?-1:f;
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num*f;
}

inline void add_edge(int u,int v,int flow)
{
    edge[++num_edge].v=v;
    edge[num_edge].flow=flow;
    edge[num_edge].nxt=head[u];
    head[u]=num_edge;
}

int dep[N];
inline bool bfs()
{
//    for(int i=1;i<=N;++i)
//        front[i]=head[i],
    memset(dep,0,sizeof(dep));
    queue<int> que;
    que.push(S),dep[S]=1;
    int now,v;
    while(!que.empty())
    {
        now=que.front(),que.pop();
        for(int i=head[now];i;i=edge[i].nxt)
        {
            v=edge[i].v;
            if(!dep[v]&&edge[i].flow)
            {
                dep[v]=dep[now]+1;
                if(v==T)
                    return 1;
                que.push(v);
            }
        }
    }
    return 0;
}

int dfs(int now,int flow)
{
    if(now==T||!flow)
        return flow;
    int outflow=0,v,tmp;
    for(int i=head[now];i;i=edge[i].nxt)
    {
        if(edge[i].flow)
        {
            v=edge[i].v;
            if(dep[v]!=dep[now]+1)
                continue;
            tmp=dfs(v,min(flow,edge[i].flow));
            flow-=tmp;
            outflow+=tmp;
            edge[i].flow-=tmp;
            edge[i^1].flow+=tmp;
            if(!flow)
                return outflow;
        }
    }
    dep[now]=0;
    return outflow;
}

int a;
int main()
{
    num_edge=1;
    n=read();
    S=0,T=3005;
    for(int i=1;i<=n;++i)
    {
        a=read();
        V+=a;
        add_edge(S,i,a);
        add_edge(i,S,0);
    }
    for(int i=1;i<=n;++i)
    {
        a=read();
        V+=a;
        add_edge(i,T,a);
        add_edge(T,i,0);
    }
    m=read();
    for(int i=1,k,c1,c2,id,P,Q,flow;i<=m;++i)
    {
        flow=0;
        P=i+n,Q=i+n+m;
        k=read(),c1=read(),c2=read();
        V+=c1+c2;
        add_edge(S,P,c1);
        add_edge(P,S,0);
        add_edge(Q,T,c2);
        add_edge(T,Q,0);
        while(k--)
        {
            id=read();
            add_edge(P,id,INF);
            add_edge(id,P,0);
            add_edge(id,Q,INF);
            add_edge(Q,id,0);
        }
    }
    while(bfs())
        V-=dfs(S,INF);
    printf("%d",V);
    return 0;
}

 

posted @ 2018-03-22 14:30  whymhe  阅读(242)  评论(0编辑  收藏  举报