• BZOJ 3438 小M的作物 & BZOJ 1877 [SDOI2009]晨跑


       我由衷地为我的朋友高兴。哈哈,yian,当你nick name破百上千时,再打“蒟蒻”就会被打的。

      好的,说正事吧。请注意,这还是题解。但我发现,网络流实在是太套路了(怪不得这两年几乎销声匿迹)。我们将分析两道题目,分别代表两类稍微有一点思想意义的题目。

      啊啊啊啊啊。


     3438: 小M的作物

    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

    Sample Output

    11
    样例解释A耕地种1,2,B耕地种3,收益4+2+3+2=11。
    1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。

      这道题可能代表了BZOJ上的一类题,就像之前所说过的BZOJ 3894 文理分科一样,与BZOJ 1497 [NOI2006]最大获利也颇有类似之处。

      这是最大负权回路:

      而此题则是另一种策略。好水啊


    1877: [SDOI2009]晨跑

    Description

    Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。

    Input

    第一行:两个数N,M。表示十字路口数和街道数。 
    接下来M行,每行3个数a,b,c,表示路口a和路口b之间有条长度为c的街道(单向)。
    N ≤ 200,M ≤ 20000。

    Output

    两个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长度。

    Sample Input

    7 10
    1 2 1
    1 3 1
    2 4 1
    3 4 1
    4 5 1
    4 6 1
    2 5 5
    3 6 6
    5 7 1
    6 7 1

    Sample Output

    2 11

      啊啊啊。这是典型的费用流。因为限制访问次数,所以需要拆点,其间边流量为1(源点汇点为inf)费用为0。点之间正常连边,边流量为1(我最开始想用inf,结果因为各种原因WA了)费用为题中所述的c。
      费用流其实就是反复做普通的SPFA(用cost作边权),不过更新时需保证u->v这条弧的cap>flow,另需多维护其来路,其流量。然后flow加上汇点t的流量增量,cost加上汇点t的流量增量*汇点t到源点s的距离(路径cost之和)。然后一条一条边倒回去,处理各边的flow。
      挂个代码吧。
     1 /**************************************************************
     2     Problem: 1877
     3     User: Doggu
     4     Language: C++
     5     Result: Accepted
     6     Time:1484 ms
     7     Memory:4856 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #include <cstring>
    12 #include <algorithm>
    13  
    14 const int N = 100010;
    15 const int M = 100010;
    16 struct Edge {int v,u,upre,cap,flow,cost;}g[M];
    17 int head[N], ne=-1;
    18 inline void adde(int u,int v,int cap,int cost) {
    19     g[++ne]=(Edge){v,u,head[u],cap,0,cost},head[u]=ne;
    20     g[++ne]=(Edge){u,v,head[v],0,0,-cost},head[v]=ne;
    21 }
    22  
    23 int d[N], p[N], a[N];
    24 bool inq[N];
    25 #include <queue>
    26 std::queue<int> q;
    27 bool SPFA(int s,int t,int &flow,int &cost) {
    28     while(!q.empty()) q.pop();
    29     memset(inq,0,sizeof(inq));
    30     memset(d,127/2,sizeof(d));
    31     q.push(s);inq[s]=1;d[s]=0;p[s]=0;a[s]=0x3f3f3f3f;
    32     while(!q.empty()) {
    33         int u=q.front();q.pop();inq[u]=0;
    34         for( int i = head[u]; i!=-1; i=g[i].upre ) {
    35             int v=g[i].v;
    36             if(g[i].cap>g[i].flow&&d[v]>d[u]+g[i].cost) {
    37                 if(!inq[v]) q.push(v),inq[v]=1;
    38                 d[v]=d[u]+g[i].cost;p[v]=i;a[v]=std::min(a[u],g[i].cap-g[i].flow);
    39             }
    40         } 
    41     }
    42     if(d[t]==d[N-1]) return false;
    43     flow+=a[t];cost+=d[t]*a[t];
    44     int u = t;
    45     while(u != s) {
    46         g[p[u]].flow+=a[t];
    47         g[p[u]^1].flow-=a[t];
    48         u=g[p[u]].u;
    49     } 
    50     return true;
    51 }
    52 void MxfMnc(int s,int t) {
    53     int flow = 0, cost = 0;
    54     while(SPFA(s,t,flow,cost));
    55     printf("%d %d
    ",flow,cost);
    56 }
    57  
    58  
    59 int main() {
    60     memset(head,-1,sizeof(head));
    61     int n, m, a, b, c;scanf("%d%d",&n,&m);
    62     adde(1,n+1,0x3f3f3f,0);for( int i = 2; i < n; i++ ) adde(i,n+i,1,0);
    63     for( int i = 1; i <= m; i++ ) {
    64         scanf("%d%d%d",&a,&b,&c);
    65         adde(n+a,b,1,c);
    66     }
    67     MxfMnc(1,n);
    68     return 0;
    费用流
  • 相关阅读:
    编程之美3.7 队列中最大值问题
    群聊天
    POJ 3384 Feng Shui 半平面交
    Fiberead
    熊猫资本李论:为何我不看好“轻轻家教”模式?_亿欧网_驱动创业创新
    轻轻家教_百度百科
    为什么我们要使用新型Web安全协议HSTS?
    http://www.doframe.com/jetoolweb/index.html
    http://www.16aspx.com/Code/Show/5352
    http://www.ybtsoft.com/
  • 原文地址:https://www.cnblogs.com/Doggu/p/bzoj3438bzoj1877.html
Copyright © 2020-2023  润新知