1. 程式人生 > >Codeforces 724E 最大流=最小割+dp求最小割

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;j<i;j++){ f[i][j]=min(f[i-1][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 <bits/stdc++.h>
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; }