[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个整数,表示该组合中的作物编号。

 

输出格式:

 

只有一行,包括一个整数,表示最大收益

 

输入输出样例

输入样例#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。

//本题是第二种常见网络流建图方式(第一种是二分图最佳/最大匹配)

//分别对应最大/费用流

//这种模型的同类题还有艾泽拉斯刀妹阿狸(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 }

 

 

posted @ 2018-04-10 14:50  zZ1358m  阅读(147)  评论(0编辑  收藏  举报