BZOJ3438 小M的作物

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3438

 

这题觉得和上题有点类似吧。

如果没有联合在一起的收成,可以比较好做[我们将属于A的表示到s集中,属于B的表示到t集中]:

  s往所有i连a[i],所有i往t连b[i]。

这样的话,割集表示不选哪些,最后答案就是ans-最小割

 

现在考虑联合在一起的收成。

我们对于收成(wa,wb),我们把它拆成两个点u,v,一个与s相连,边权为wa,另一个与t相连,边权为wb。

但是我们需要保证当我选择wa的收益时,需要将令所有关于它的点都不能放在t集合里;当我们选择wb的收益时,需要令所有关于它的点都不在s集合里。

那么怎么构图呢?

就将u往所有相关的i连一条INF的边,所有i往v连一条INF的边。

 

自从看了那篇有趣的博客,我觉得画图就应该这样画意识流...

 

这一题RE了很多次,原因就是数组开小了。

边集究竟有多大呢?以最坏的恶意,那么每个收益都是全体点的,那么就是m*n*2条边,然后每个点也要连出去两条,就是(m*n*2+n*2)*2=(2000000+2000)*2=4004000,然后总共的点数是n+2*m=3000个点。

以后要多想一想再来开数组啊....

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

inline int in(){
    int x=0;char ch=getchar();
    while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

const int maxn=3010;
const int INF=0x3f3f3f3f;

struct Node{
    int data,next,low;
}node[4000010];

#define now node[point].data
#define then node[point].next
#define www node[point].low

int n,m,cnt,ans;
int s,t,Idex;
int w1[maxn],w2[maxn];
int cur[maxn],head[maxn];
int dis[maxn],que[maxn];

void add(int u,int v,int w){
    node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;
    node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++;
}

bool BFS(){
    memset(dis,-1,sizeof(dis));
    int H=0,T=1;que[1]=0,dis[0]=0;
    while(H<T){
        H++;
        for(int point=head[que[H]];point!=-1;point=then)
            if(www && dis[now]<0){
                dis[now]=dis[que[H]]+1;
                que[++T]=now;
            }
    }
    return dis[t]>0;
}

int dfs(int x,int low){
    if(x==t) return low;
    int Low;
    for(int &point=cur[x];point!=-1;point=then)
        if(www && dis[now]==dis[x]+1){    
            Low=dfs(now,min(low,www));
            if(Low){
                www-=Low,node[point^1].low+=Low;
                return Low;
            }
        }
    return 0;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("3438.in","r",stdin);
    freopen("3438.out","w",stdout);
#endif

    n=in();
    for(int i=1;i<=n;i++) w1[i]=in(),ans+=w1[i];
    for(int i=1;i<=n;i++) w2[i]=in(),ans+=w2[i];
    m=in();
    t=n+(m<<1)+1;
    for(int i=s;i<=t;i++) head[i]=-1;
    for(int i=1;i<=n;i++)
        add(s,i,w1[i]),add(i,t,w2[i]);
    Idex=n;
    int k,wa,wb,x;
    for(int i=1;i<=m;i++){
        k=in(),wa=in(),wb=in();
        Idex++;add(s,Idex,wa);ans+=wa;
        Idex++;add(Idex,t,wb);ans+=wb;
        while(k--){
            x=in();
            add(Idex-1,x,INF),add(x,Idex,INF);
        }
    }
    int flag;
    while(BFS()){
        for(int i=s;i<=t;i++) cur[i]=head[i];
        while(1){
            flag=dfs(s,INF);
            if(!flag) break;
            ans-=flag;
        }
    }
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2016-02-26 16:19  诚叙  阅读(743)  评论(1编辑  收藏  举报