Codeforces 724E 最大流=最小割+dp求最小割

题意:
有n个城市,每个城市有p【i】的东西,可以在那个城市卖c【i】的东西,两两城市可以进行一次c的运送,只能从小的编号的往大的编号运。
问最多能卖多少货物。
思路:
最大流:建图,s到n个城市为p【i】然后n个城市到t为s【i】,小的编号到大的编号两两为c,
因为图太大,会超内存,所以就用dp求最小割=最大流
这里先证明一下最小割的情况,一定是每个点只连s或者t:
因为如果两个都割掉的,肯定有一个是多余,这个自己画一下图感受下即可。
所以写dp方程。
dp【i】【j】为前i个城市在最小割之后,有j个城市在与s相连,
dp【i】【j】=min(dp【i-1】【j-1】+s【i】,dp【i-1】【j】+j*c+p【i】)
然后这样的话仍会超内存,所以用滚动数组,注意循环的顺序。
先来不用滚动数组的:

int n;
long long c;
long long p[10010],s[10010];
long long f[10010][10010],ans;



int main()
{
    scanf("%d%I64d",&n,&c);
    for (int i=1; i<=n; i++) scanf("%d",&p[i]);
    for (int i=1; i<=n; i++) scanf("%d",&s[i]);
    for (int i=1; i<=n; i++)
    {
        f[i][0]=f[i-1][0]+p[i];
        for(int j=1;j1][j]+j*c+p[i],f[i-1][j-1]+s[i]);
        }
        f[i][i]=f[i-1][i-1]+s[i];
    }
    ans=1000000000000;
    for (int i=0;i<=n; i++) ans=min(ans,f[n][i]);
    printf("%I64d",ans);
    return 0;
}

滚动数组:

#include 
using namespace std;

int n;
long long c;
long long p[10010],s[10010];
long long f[10010],ans;



int main()
{
    scanf("%d%I64d",&n,&c);
    for (int i=1; i<=n; i++) scanf("%I64d",&p[i]);
    for (int i=1; i<=n; i++) scanf("%I64d",&s[i]);
    for (int i=1; i<=n; i++)
    {
        f[i]=1e18;
        for(int j=i;j>=1;j--){
            f[j]=min(f[j]+j*c+p[i],f[j-1]+s[i]);
        }
        f[0]+=p[i];
    }
    ans=1e18;
    for (int i=0;i<=n; i++) ans=min(ans,f[i]);
    printf("%I64d",ans);
    return 0;
}

你可能感兴趣的:(Codeforces 724E 最大流=最小割+dp求最小割)