[BZOJ3438] 小M的作物
bzoj 3438 小M的农场
小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个整数,表示该组合中的作物编号。
输出格式:
只有一行,包括一个整数,表示最大收益
输入输出样例
说明
样例解释
A耕地种1,2,B耕地种3,收益4+2+3+2=11。
数据范围与约定
1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
//本题是第二种常见网络流建图方式(第一种是二分图最佳/最大匹配)
//分别对应最大/费用流
//这种模型的同类题还有艾泽拉斯刀妹阿狸(qbxt的一道题)
//中间点要么左要么右所以采取虚拟源点向n个初始点引容量为权值的线
//汇点同理
//对于组合,采取合成虚拟点办法
//如果两点一左一右更优了就不会这么跑了()
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<queue> 6 #include<cstdio> 7 #define maxn 10005 8 #define maxm 100005 9 #define inf 200000000 10 using namespace std; //11-88行为最大流模板 大体说一下就是用弧的阻塞流来进行增广 dinic 复杂度实际为差不多 n^1/2(二分图)左右 m 理论 也不大 n^2m 11 struct edge{ 12 int from; int to; int flow; int cap; 13 }; 14 int cur[maxn],d[maxn],a[maxn],b[maxn]; 15 bool vis [maxn]; 16 int m=0,n,c,k,s,t,sum,ans; 17 int kk,x,c1,c2; 18 vector <int> g[maxn]; 19 vector <edge> edges; 20 void add_edge(int a,int b,int c) 21 { 22 m+=2; 23 edges.push_back({a,b,0,c}); 24 edges.push_back({b,a,0,0});//反弧 不必求甚解 25 g[b].push_back(m-1); 26 g[a].push_back(m-2); 27 } 28 bool BFS() { 29 //要建立分层次的图 相当于货架上一层一层的面包。。 30 memset(vis,0,sizeof(vis)); 31 queue <int> q; 32 q.push(s); 33 d[s]=0; 34 vis[s]=1; 35 while(! q.empty()) { 36 int u=q.front();q.pop(); 37 for(int i=0;i<g[u].size();i++) 38 { 39 if(!vis[edges[g[u][i]].to]&&edges[g[u][i]].cap>edges[g[u][i]].flow) 40 { 41 d[edges[g[u][i]].to]=d[u]+1; 42 vis[edges[g[u][i]].to]=1; 43 q.push(edges[g[u][i]].to); 44 } 45 } 46 } 47 return vis[t]; 48 } 49 long long dfs(int x,int a) { 50 //对于所有的弧深度遍历; 51 if (x==t || a==0) return a; 52 long long flow=0; 53 int f; 54 for(int &i=cur[x]; i< g[x].size(); i++) 55 { 56 if (d[x]+1==d[edges[g[x][i]].to] && (f=dfs(edges[g[x][i]].to,min(a,edges[g[x][i]].cap-edges[g[x][i]].flow)))>0) 57 { 58 edges[g[x][i]].flow+=f; 59 edges[g[x][i]^1].flow-=f; 60 flow+=(long long)1*f; 61 a-=f; 62 if (a==0) break; 63 } 64 } 65 return flow; 66 } 67 int maxflow(int s,int t) 68 { 69 long long flow=0; 70 while(BFS()==1) 71 { 72 memset(cur,0,sizeof(cur)); 73 flow+=(long long)dfs(s,inf); 74 } return flow; 75 } 76 int main() 77 { 78 sum=0; 79 ios::sync_with_stdio(false); cin>>n;//呵呵呵典型全cin的c++风格 80 for (int i=1;i<=n;i++) { cin>>a[i];sum+=a[i]; } 81 for (int i=1;i<=n;i++) { cin>>b[i];sum+=b[i]; } 82 cin>>k; 83 s=0;t=n+2*k+1; 84 for (int i=1;i<=n;i++) 85 add_edge(s,i,b[i]),add_edge(i,t,a[i]); 86 for (int i=1;i<=k;i++) 87 { 88 cin>>kk>>c1>>c2 ; 89 add_edge(s,n+i*2,c2);add_edge(n+i*2-1,t,c1); 90 sum+=c1+c2; 91 for (int j=1;j<=kk;j++) 92 { 93 cin>>x; 94 add_edge(x,n+i*2-1,inf);add_edge(n+i*2,x,inf); 95 } 96 } 97 int flow=maxflow(s,t); 98 cout<<sum-flow<<endl; 99 return 0; 100 }