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;
}
原文地址:https://www.cnblogs.com/hua-dong/p/8653682.html