首页 > 技术文章 > 题解 CF724E 【Goods transportation】

lhm- 2020-08-24 19:16 原文

先考虑一种网络流解法,从源点 \(S\) 向每个点连容量为 \(p_i\) 的边,每个点向汇点连容量为 \(s_i\) 的边,每个点向编号比其大的点连容量为 \(c\) 的边,该图的最大流即为答案。

但是复杂度无法接受,考虑换一种思路,观察建出的图:

发现这张图比较特殊,像最小割的模型,考虑将求最大流转为求最小割,用考虑 \(DP\) 来解决。设 \(f_{i,j}\) 为考虑了前 \(i\) 个点,有 \(j\) 个点与源点相连的最小割花费,得转移方程为:

\[\large f_{i,j}=\min\left(f_{i-1,j-1}+s_i,f_{i-1,j}+p_i+jc\right) \]

即转移为点 \(i\) 是和源点相连还是和汇点相连。\(DP\) 数组开不下,需要用滚动数组。

#include<bits/stdc++.h>
#define maxn 10010
#define inf 10000000000000000
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
ll n,c,x,ans=inf;
ll p[maxn],s[maxn],f[2][maxn];
int main()
{
    read(n),read(c);
    for(int i=1;i<=n;++i) read(p[i]);
    for(int i=1;i<=n;++i) read(s[i]);
    for(int i=1;i<=n;++i,x^=1)
    {
        f[x][0]=f[x^1][0]+p[i];
        for(int j=1;j<=n;++j) f[x][j]=inf;
        for(int j=1;j<=i;++j)
            f[x][j]=min(f[x^1][j-1]+s[i],f[x^1][j]+p[i]+j*c);
    }
    for(int i=0;i<=n;++i) ans=min(ans,f[x^1][i]);
    printf("%lld",ans);
    return 0;
}

推荐阅读