題目描述
小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。
題解:這是一道關於最小割的網絡流
假設現在有兩個陣營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;
}