[HAOI2010][bzoj2424] 订货 [费用流]

题面

传送门

思路

这题其实挺水的......做过餐巾计划问题就能明白,是同一个道理

首先,显然刚刚好满足每一个月的需求,会得到最优解(废话-_-||)

然后我们发现,货物在不同的月之间的转移,可以比喻为水在不同的几个平行管道之间流动

自然而然地想到网络流

那么,我们给每个月建立一个节点i,建立超级源点和超级汇点

从每个i连边(i,T),费用0,流量为这个月需求量

从S向每个月连边(S,i),费用为这个月的价格,流量无限(因为理论上你随便买都可以)

那么储存就是连边(i,i+1),费用为m,流量为S,这里的流量也很好地体现了限制作用

最后的答案就是(S-T)最小费用最大流了

需要注意的是,这道题里面的流量提供了两个限制:

一个是每个月可以买很多,但是我们输出只有要求的那么多,是一个下限转上限

另一个就是仓库容量,这个是直接把上限用流量表示出来了

由此,我们应当注意到,网络流中的流量上限其实不止可以表示一种决策的最大值

它也可以在一定的贪心和推导以后来表示最小值

所以做题的时候思路一定要大胆一些

说不定这就是个网络流题呢?

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 1e9
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
int first[5010],dis[5010],vis[5010],n,m,cnt=-1,ans;
struct edge{
    int to,next,w,cap;
}a[600010];
inline void add(int u,int v,int w,int cap){
    a[++cnt]=(edge){v,first[u],w,cap};first[u]=cnt;
    a[++cnt]=(edge){u,first[v],-w,0};first[v]=cnt;
}
int q[1000010];
bool spfa(int s,int t){
    int head=0,tail=1,i,u,v,w;
    memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis));
    q[0]=t;dis[t]=0;vis[t]=1;
    while(head<tail){
        u=q[head++];vis[u]=0;
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;w=a[i].w;
            if(a[i^1].cap&&((dis[v]==-1)||(dis[v]>dis[u]-w))){
                dis[v]=dis[u]-w;
                if(!vis[v]) q[tail++]=v,vis[v]=1;
            }
        }
    }
    return ~dis[s];
}
int _min(int l,int r){return (l>r)?r:l;}
int dfs(int u,int t,int limit){
    if((u==t)||(!limit)){vis[u]=1;return limit;}
    int i,v,f,flow=0,w;vis[u]=1;
    for(i=first[u];~i;i=a[i].next){
        v=a[i].to;w=a[i].w;
        if(dis[v]==dis[u]-w&&a[i].cap&&!vis[v]){
            if(!(f=dfs(v,t,_min(limit,a[i].cap)))) continue;
            a[i].cap-=f;a[i^1].cap+=f;
            ans+=f*w;flow+=f;limit-=f;
            if(!limit) return flow;
        }
    }
    return flow;
}
int zkw(int s,int t){
    int re=0;
    while(spfa(s,t)){
        vis[t]=1;
        while(vis[t]){
            memset(vis,0,sizeof(vis));
            re+=dfs(s,t,inf);
        }
    }
    return re;
}
int main(){
    memset(first,-1,sizeof(first));
    n=read();m=read();int S=read(),i,t1;
    for(i=1;i<=n;i++) t1=read(),add(i,n+1,0,t1);
    for(i=1;i<=n;i++) t1=read(),add(0,i,t1,inf);
    for(i=1;i<n;i++) add(i,i+1,m,S);
    zkw(0,n+1);
    cout<<ans<<endl;
}
posted @ 2018-04-08 18:16  dedicatus545  阅读(133)  评论(0编辑  收藏  举报