题解 P1361 【小M的作物】
YoungNeal
2018-04-16 22:00:36
题解在博客[食用](http://www.cnblogs.com/YoungNeal/p/8858838.html)效果更佳哦~
好题~
最开始想的费用流结果会答案会变大,看了题解才知道跟最小割有关
我们把源点当做 A 田地,汇点当做 B 田地。
对于作物 i,如果种在 A 的价值是 a[i],种在 B 的价值是 b[i],那么就从它向 A 连一条容量为 a[i] 的边,同理,向 B 连一条容量为 b[i] 的边。
为什么要这么做呢?考虑最后的答案,一个点向外连出的两条边必定会有一条被割掉,不然这个点连着两边,相当于两边都种,不符合题意,所以这种情况不符合题意。
必定有一条会被割掉...咦这不是最小割么?
那么我们已经初步转化问题了,即已经把问题转化到最小割上了。
接下来考虑组合的问题。
其实组合也一样,就是让这个组合也分成向 A,B 连边两部分。
先把这个组合拆点。然后其中一个点的入边连上 A,容量是组合种在 A 的额外价值,出边连上这个组合里所有的点,容量是 INF。 B 也是同理。
那么我们就彻底把问题转化了最小割了。但是这题要让 ans 最大,怎么办呢?
好说,把总收益加起来,减去最小割就好了。
```
// By YoungNeal
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define N 10005
#define inf 0x3f3f3f3f-1
int tot;
int d[N];
int cnt=1;
int dis[N];
int head[N];
int n,m,s,t;
struct Edge{
int to,nxt,flow;
}edge[4400000];
void add(int x,int y,int z){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
edge[cnt].flow=z;
head[x]=cnt;
}
bool bfs(){
memset(d,0,sizeof d); d[s]=1;
std::queue<int> q; q.push(s);
while(q.size()){
int u=q.front();q.pop();
for(int i=head[u];i;i=edge[i].nxt){
int to=edge[i].to;
if(!edge[i].flow) continue;
if(d[to]) continue;
d[to]=d[u]+1;
q.push(to);
if(to==t) return 1;
}
}
return 0;
}
int dinic(int now,int flow){
if(now==t) return flow;
int rest=flow;
for(int i=head[now];i;i=edge[i].nxt){
if(!rest) return flow;
int to=edge[i].to;
if(!edge[i].flow) continue;
if(d[to]!=d[now]+1) continue;
int k=dinic(to,std::min(rest,edge[i].flow));
if(!k) d[to]=0;
rest-=k;
edge[i].flow-=k;
edge[i^1].flow+=k;
}
return flow-rest;
}
signed main(){
scanf("%d",&n); s=n+1; t=s+1;
for(int x,i=1;i<=n;i++) scanf("%d",&x),tot+=x,add(s,i,x),add(i,s,0);
for(int x,i=1;i<=n;i++) scanf("%d",&x),tot+=x,add(i,t,x),add(t,i,0);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int T,tota,totb;
scanf("%d%d%d",&T,&tota,&totb);
tot+=tota+totb;
add(s,n+2+i,tota); add(n+2+i,s,0);
add(n+2+i+m,t,totb); add(t,n+2+i+m,0);
for(int x,j=1;j<=T;j++){
scanf("%d",&x);
add(n+2+i,x,inf);
add(x,n+2+i,0);
add(x,n+2+i+m,inf);
add(n+2+i+m,x,0);
}
}
int maxflow=0,flow=0;
while(bfs())
while(flow=dinic(s,0x3f3f3f3f)) maxflow+=flow;
printf("%d\n",tot-maxflow);
return 0;
}
```