Codeforces 724E 最大流=最小割+dp求最小割
阿新 • • 發佈:2019-01-06
題意:
有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;
}