洛谷__P1361 小M的作物

https://www.luogu.org/

題目描述

小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。

problem/P1361

 

題解:這是一道關於最小割的網絡流

假設現在有兩個陣營S,T。 士兵a加入S陣營的價值是c1,加入T陣營的是c3,而士兵b加入S陣營的價值是c2,加入T的是c4,

求怎麼分配a,b,使得總價值最大

我們可以這樣建圖,S向a,b連邊,a,b向T連邊,如圖

 

這樣的話最大收益就是  圖上的邊(總收益)加起來減去最小割(也就是最大流)

現在問題升級了,若a,b同時加入S陣營可以多收益p1,同時加入T陣營可以多收益p2,那麼怎麼才能使收益最大呢

ps:額外的收益肯定不能繼續加在上面的節點上,所以我們新建一個臨時結點x,然後從S連上權值爲p1的邊到x

新建一個臨時y,然後連一條權值p2的邊到T,如圖所示

假如a或b有一個不在S陣營,那麼p1就會斷掉,所以x與a,b相連的兩條邊設爲無窮就可以不被斷掉,同理T陣營的也是,這樣用總收益減去最小割就是答案了(可以自己照着圖想下就可以理解了)

#include <bits/stdc++.h>

using namespace std;

const int maxn = 3e6+9;
const int INF = 0x3f3f3f3f;

int a[maxn],b[maxn];

int head[maxn],cur[maxn];
int tot=0;
struct rt{
    int next,v,c;
}edge[maxn];

void add_edge(int u,int v,int c){
    edge[tot].v=v;
    edge[tot].c=c;
    edge[tot].next=head[u];
    head[u]=tot++;
}

int level[maxn];

bool bfs(int s,int t){
    for(int i=0;i<=t+100;i++)level[i]=-1;
    level[s]=0;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front(); que.pop();
        if(u==t)break;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(level[v]==-1&&edge[i].c>0){
                level[v]=level[u]+1;
                que.push(v);
            }
        }
    }
    if(level[t]==-1)return false;
    return true;
}

int dfs(int u,int t,int f){
    if(u==t)return f;
//    int add=0,tempflow;
    for(int &i=cur[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(level[v]>level[u]&&edge[i].c>0){
            int d=dfs(v,t,min(f,edge[i].c));
            if(d>0){
                edge[i].c-=d;
                edge[i^1].c+=d;
                return d;
            }
        }
    }
    return 0;
}

int dinic(int s,int t){
    int max_flow=0;
    while(bfs(s,t)){
//            cout<<777<<endl;
        int flow;
        for(int i=0;i<=t+10;i++){
            cur[i]=head[i];
        }
        while((flow=dfs(s,t,INF))>0){
            max_flow+=flow;
        }
    }
    return max_flow;
}

int main(){
    memset(head,-1,sizeof(head));
    int n,m;
    int sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
    for(int i=1;i<=n;i++)scanf("%d",&b[i]),sum+=b[i];
    scanf("%d",&m);
    int s=0,t=n+2*m+100;
    for(int i=1;i<=n;i++){
        add_edge(s,i,a[i]);
        add_edge(i,s,0);
    }
    for(int i=1;i<=n;i++){
        add_edge(i,t,b[i]);
        add_edge(t,i,0);
    }
    int k,c1,c2;
    for(int i=1,j=n+1;i<=m;i++,j+=2){
        scanf("%d",&k);
        scanf("%d%d",&c1,&c2);
        sum+=(c1+c2);
        add_edge(s,j,c1);
        add_edge(j,s,0);

        add_edge(j+1,t,c2);
        add_edge(t,j+1,c2);

        int x;
        for(int l=0;l<k;l++){
            scanf("%d",&x);
            add_edge(j,x,INF);
            add_edge(x,j,0);

            add_edge(x,j+1,INF);
            add_edge(j+1,x,0);
        }
    }
//    cout<<555<<endl;
    printf("%d\n",sum-dinic(s,t));
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章