zoukankan      html  css  js  c++  java
  • 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

     
  • 相关阅读:
    rocketmq的broker如何同步信息的?
    SO_LINGER 选项
    哈哈哈
    NAG博客目录
    事后分析$eta$
    项目展示$eta$
    测试报告$eta$
    发布声明$eta$
    Scrum meeting 10
    技术博客6--Django实现列表分页
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6760224.html
Copyright © 2011-2022 走看看