[codeforces724e]Goods transportation 解题报告

这题好神呀。

首先这是一个网络流模型,考虑每个点都向编号比它大的点连一条容量为c的边,然后如果 pisi ,就从source向i连一条容量为 pisi 的边,否则就从i向sink连一条容量为 sipi 的边,这样的话最大流就是答案。
但是这个图太大了,不能直接跑最大流,也无法优化。
所以我们可以转而考虑最小割,我们发现如果我们知道了割中的点是哪些,其实是可以直接算出割的大小的。
所以如果设f(i,j)表示前i个点,S中有j个的最小割。那么

f(i,j)={min(f(i1,j)+pisi+jc,f(i1,j1)),pisimin(f(i1,j)+jc,f(i1,j1)+sipi),pi<si

代码:

#include<stdio.h>
#include<iostream>
using namespace std;
#include<algorithm>
const int N=1e4+5;
int p[N],s[N];
typedef long long LL;
LL f[N];
int main()
{
    //cout<<(sizeof(rest)>>20)<<endl;

    //freopen("cf724e.in","r",stdin);
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;++i)scanf("%d",p+i);
    for(int i=1;i<=n;++i)scanf("%d",s+i);

    LL ans=0;
    for(int i=1;i<=n;++i)
    {
        ans+=min(s[i],p[i]);

        if(s[i]<=p[i])f[i]=f[i-1];
        else f[i]=f[i-1]+s[i]-p[i];

        for(int j=i-1;j>=0;--j)
            if(s[i]<=p[i])
            {
                f[j]+=p[i]-s[i]+(LL)j*c;
                if(j)f[j]=min(f[j],f[j-1]);
            }
            else{
                f[j]+=(LL)j*c;
                if(j)f[j]=min(f[j],f[j-1]+s[i]-p[i]);
            }

        //for(int j=0;j<=i;++j)printf("f(%d,%d)=%I64d\n",i,j,f[j]);
    }
    cout<<(ans+*min_element(f,f+n+1))<<endl;
}

总结:
①。。感觉经常想不到网络流呢。什么样的题要用网络流呢?也许是方案非常复杂的那种吧,就像这道题。所以如果感觉方案很鬼畜难以统计就考虑一下网络流吧!
②注意最大流与最小割的转化。

猜你喜欢

转载自blog.csdn.net/ta201314/article/details/52780989
今日推荐