zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    哈希冲突详解(拉链法,开放地址法)
    哈希冲突详解(拉链法,开放地址法)
    排序算法
    排序算法
    加分二叉树
    加分二叉树
    动态规划
    动态规划
    动态规划
    动态规划
  • 原文地址:https://www.cnblogs.com/iboom/p/8779004.html
Copyright © 2011-2022 走看看