zoukankan      html  css  js  c++  java
  • BZOJ3438:小M的作物 (最大闭合权图->最小割)

    小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=111<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9

    思路:orzpopoqqq。假定全部在A里,然后去找增广流。  如果很好地理解了用最大流求最大闭合权图的话,就不难想通。

    最大闭合权图:原点与代价点连接,收益点与汇点连接; 收益和-最大流=最大净收益。 那么现在的基本代价或者收益是ai-bi,。然后破坏集合的代价是c1i,得到集合的收益是c2i。 差不多就酱紫。具体的请去看popoqqq的题解。

    和BZOJ3894差不多,就不多说了:http://www.cnblogs.com/hua-dong/p/8655375.html

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=4000010;
    const long long  inf=100000000000000;
    int N,M,S,T,cnt=1;
    long long ans,maxflow,cap[maxn];
    int Laxt[maxn],To[maxn],Next[maxn],vd[maxn],dis[maxn];
    void add(int u,int v,long long c)
    {
        Next[++cnt]=Laxt[u];
        Laxt[u]=cnt;
        To[cnt]=v;
        cap[cnt]=c;
    }
    long long sap(int u,long long flow)
    {
        if(flow==0||u==T) return flow;
        long long tmp,delta=0;
        for(int i=Laxt[u];i;i=Next[i]){
            if(dis[u]==dis[To[i]]+1&&cap[i]>0){
               tmp=sap(To[i],min(cap[i],flow-delta));
                delta+=tmp;
               cap[i]-=tmp;
               cap[i^1]+=tmp;
               if(delta==flow||dis[S]>T+1) return delta; 
            }
        }
        vd[dis[u]]--;
        if(vd[dis[u]]==0) dis[S]=T+2;
        vd[++dis[u]]++;
        return delta;
    }
    int main()
    {
        int i,j,x,y,num; scanf("%d",&N);
        S=0; T=3100;
        for(i=1;i<=N;i++){
            scanf("%d",&x); ans+=x;
            add(S,i,x); add(i,S,0);
        }
        for(i=1;i<=N;i++){
             scanf("%d",&x); ans+=x;
             add(i,T,x); add(T,i,0); 
        }
        scanf("%d",&M);
        for(i=1;i<=M;i++){
            scanf("%d",&num);    
            scanf("%d%d",&x,&y);
            ans+=x+y;
            add(S,N+i,x); add(N+i,S,0);
            add(N+M+i,T,y); add(T,N+M+i,0);
            for(j=1;j<=num;j++){
                scanf("%d",&x);
                add(N+i,x,inf); add(x,N+i,0);
                add(x,N+M+i,inf); add(N+M+i,x,0);
            }    
        }
        while(dis[S]<=T) maxflow+=sap(S,inf);
        printf("%d
    ",ans-maxflow);
        return 0;
    }
  • 相关阅读:
    C#中Split用法
    ASP.NET Get和Post两种提交的区别:
    BAT常用命令
    SQL语句:在两个数据库间复制表结构和数据数据库
    C#中Array与ArrayList用法及转换
    找出输入区间内的回文质数
    (转)加藤嘉一:中国大学生,你没资格抱怨政府
    最长公共子序列(LCS)
    shell(希尔)排序
    关于Ubuntu中google chrome浏览器字体的设置
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8653682.html
Copyright © 2011-2022 走看看