bzoj 3438 小M的作物
3438: 小M的作物
http://www.lydsy.com/JudgeOnline/problem.php?id=3438
Time Limit: 10 Sec Memory Limit: 256 MB[Submit][Status][Discuss]
Description
小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
4 2 1
2 3 2
1
2 3 2 1 2
Sample Output
11
样例解释A耕地种1,2,B耕地种3,收益4+2+3+2=11。
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
样例解释A耕地种1,2,B耕地种3,收益4+2+3+2=11。
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
最大收益转化为最小损失
1、源点向作物连权值为ai的边,作物向汇点连权值为bi的边
2、将作物组合看做点,并拆为x,y,源点向x连权值为c1i的边,y向汇点连权值为c2i的边
3、对于每个作物组合中的作物k,x向k连inf边,k向y连inf边
ans= Σ ai + Σ bi + Σ c1i + Σ c2i - 最小割
inf边的作用:防止作物组合割了与a或b相连的边,其中的作物却割了与b或a相连的边
#include<cstdio> #include<queue> #include<algorithm> #define N 10001 using namespace std; const int inf=2e9+100; int n,m,src,dec; long long sum; int tot=1,front[N*4],next[N*200],to[N*200],cap[N*200]; int lev[N*4],cur[N*4]; int ai[N],bi[N]; queue<int>q; void add(int u,int v,int w) { to[++tot]=v; next[tot]=front[u]; front[u]=tot; cap[tot]=w; to[++tot]=u; next[tot]=front[v]; front[v]=tot; cap[tot]=0; } bool bfs() { for(int i=src;i<=dec;i++) cur[i]=front[i],lev[i]=-1; while(!q.empty()) q.pop(); lev[src]=0; q.push(src); int now; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=next[i]) { if(lev[to[i]]==-1&&cap[i]>0) { lev[to[i]]=lev[now]+1; if(to[i]==dec) return true; q.push(to[i]); } } } return false; } int dinic(int now,int flow) { if(now==dec) return flow; int delta,rest=0; for(int & i=cur[now];i;i=next[i]) if(lev[to[i]]>lev[now]&&cap[i]>0) { delta=dinic(to[i],min(flow-rest,cap[i])); if(delta) { cap[i]-=delta; cap[i^1]+=delta; rest+=delta; if(rest==flow) break; } } if(rest!=flow) lev[now]=-1; return rest; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&ai[i]); for(int i=1;i<=n;i++) scanf("%d",&bi[i]); scanf("%d",&m); src=0;dec=n+2*m+1; for(int i=1;i<=n;i++) { add(src,i,ai[i]); sum+=ai[i]; } for(int i=1;i<=n;i++) { add(i,dec,bi[i]); sum+=bi[i]; } int k,a,b,x; for(int i=1;i<=m;i++) { scanf("%d%d%d",&k,&a,&b); add(src,n+i,a); add(n+m+i,dec,b); sum+=a+b; while(k--) { scanf("%d",&x); add(n+i,x,inf); add(x,n+m+i,inf); } } while(bfs()) sum-=dinic(src,inf); printf("%lld",sum); }
错误:对边的数量估计错误
k可达1000,近组合中的作物连边可达1000*1000*2*2=4e6