• CF724E Goods transportation 最小割 DP


    照惯例CF的题不放原题链接。。。

    题意:一个序列上有n个点,每个点有权值pi和si。表示这个点一开始有pi个物品,最多可以卖出si个物品,每个点都可以把物品向编号更大的点运输,但是对于i < j的任意点对(i, j)最多从i到j运c个物品。求最多能卖出多少个物品。

    题解:

      如果不考虑数据范围的话,可以直接用网络流建图。s向每个点连流量为pi的边,表示一开始有pi的流量,每个点i向满足i < j的点j连流量为c的边,表示最多运送c个物品,每个点向t连流量为si的边,表示最多可以卖si个物品。

      最大流即为答案。

      但是这题数据范围过大,无法用网络流跑过,观察到这个图比较特殊,即如果我们知道了哪些点属于S集合(S在残余网络中可以到达的点),哪些点属于T集合,就可以直接算出最小割。

      即$ans = sum_{i in S}{s_{i}} + sum_{i in T}{p_{i}} + sum_{i in S}sum_{j in T}{c}$

      解释一下为什么是这样,应该是比较好理解的,从最小割这个角度来理解。

      如果一个点属于S,那么它肯定要断开与t的边,所以加上$s_{i}$,

      如果一个点属于T,那么它肯定要断开与s的边,所以加上$p_{i}$,

      如果一个点属于S,另一个点属于T,那么这两个点之间的边肯定要断开。

      因此我们设f[i][j]表示前i个点有j个属于S集的最小代价。

      那么如果这个点i我们划分到S集合里面,我们就加上$s_{i}$的代价。

      否则加上$p[i] + j cdot c$的代价,$j cdot c$表示这个点要与之前被划分到S集合里面的j个点都断开联系,因为边权都是c,所以代价就是$j cdot c$.

      转移的时候注意一下j从0开始枚举。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 10010
     5 #define LL long long
     6 
     7 int n;
     8 LL c, ans = 1e18;
     9 LL f[2][AC], s[AC], p[AC];
    10 
    11 inline int read()
    12 {
    13     int x = 0;char c = getchar();
    14     while(c > '9' || c < '0') c = getchar();
    15     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    16     return x;
    17 }
    18 
    19 inline void upmin(LL &a, LL b){
    20     if(b < a) a = b;
    21 }
    22 
    23 void pre()
    24 {
    25     n = read(), c = read();
    26     for(R i = 1; i <= n; i ++) p[i] = read();
    27     for(R i = 1; i <= n; i ++) s[i] = read();
    28 }
    29 
    30 void work()
    31 {
    32     int now = 0;
    33     for(R i = 1; i <= n; i ++)
    34     {
    35         now ^= 1;
    36         memset(f[now], 63, sizeof(f[now]));
    37         for(R j = 0; j <= i; j ++)
    38             if(!j) f[now][j] = f[now ^ 1][j] + p[i];
    39             else f[now][j] = min(f[now ^ 1][j] + p[i] + j * c, f[now ^ 1][j - 1] + s[i]);
    40     }
    41     for(R i = 0; i <= n; i ++) upmin(ans, f[now][i]);
    42     printf("%lld
    ", ans);
    43 }
    44 
    45 int main()
    46 {
    47     freopen("in.in", "r", stdin);
    48     pre();
    49     work();
    50     fclose(stdin);
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    2020软件工程作业04
    2020软件工程作业03
    2020软件工程作业02
    2020软件工程作业01
    2020软件工程作业02
    2020软件工程作业01
    WEB学习路线2019完整版(附视频教程+网盘下载地址)
    (2018干货系列七)最新大数据学习路线整合
    (2018干货系列六)最新云计算学习路线整合
    (2018干货系列五)最新UI设计学习路线整合
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9965918.html
Copyright © 2020-2023  润新知