Description
给出n个点,第i个点原来有p[i]个“good”(我也不知道为什么要叫这个名字,看来是Chinese round吧),可以售出s[i]个“good”。对于两个点i,j(i < j),你可以一次从i最多运送j个“good”到j,注意每对点只能运一次,求最多售出多少个“good”。
n<=10^4
Solution
这道题不是显然的最大流嘛~~
从源点向每个点连p[i],从每个点向汇点连s[i],然后每个点向后面的所有点连c,最大流就是答案。。。
但是,图的规模太大了,无法兹瓷,也不能动态开点TAT
肿么办呢?
我们注意到,最大流等于最小割!
然后这种图的最小割是可以用dp来求出来的!
设F[i][j]表示前i个点,有j个在S集里的最小割。
然后,我们把建模稍微改一下,先把能流的都流走,也就是源点向每个p[i] > s[i]的点连p[i]-s[i],每个p[i] < s[i]的点向汇点流s[i]-p[i]。
那么转移方程就显然了,判断一个点是在哪个集合中,自己手(kan)推(biao)一下就好了
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=1e4+5;
const ll inf=1e14;
ll f[2][N],p[N],s[N],ans,Min;
int n,c;
int main() {
scanf("%d%d",&n,&c);
fo(i,1,n) scanf("%I64d",&p[i]);
fo(i,1,n) scanf("%I64d",&s[i]);
fo(i,1,n) {
ans+=min(s[i],p[i]);int x=i%2,y=1-i%2;
fo(j,0,i) {
f[x][j]=inf;
if (p[i]>s[i]) {
if (j!=i) f[x][j]=min(f[x][j],f[y][j]+p[i]-s[i]+(ll)j*c);
if (j) f[x][j]=min(f[x][j],f[y][j-1]);
} else {
if (j!=i) f[x][j]=min(f[x][j],f[y][j]+(ll)j*c);
if (j) f[x][j]=min(f[x][j],f[y][j-1]+s[i]-p[i]);
}
}
}
Min=f[n%2][0];
fo(i,1,n) Min=min(Min,f[n%2][i]);
printf("%I64d\n",Min+ans);
}

本文介绍了一种解决特殊最大流问题的方法,通过DP求最小割来间接获取最大流值。该问题涉及n个点的商品销售与运输,需确定最大销售数量。文中提供了解决方案的思路与代码实现。
12万+





