zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    oc-autorelease
    oc-循环引用问题
    oc-内存管理总结
    tomcat-各文件夹作用解析
    oc-多对象内存管理
    oc-arc(Automatic Reference Counting 自动引用机制) 与 内存管理
    tomcat-context.xml
    oc-set方法内存管理 和 @property的参数
    【转载】java学习线路
    一段shell脚本
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8623623.html
Copyright © 2011-2022 走看看