「網絡流 24 題」餐巾計劃

一個餐廳在相繼的n 天裏,每天需用的餐巾數不盡相同。假設第i 天需要ri 塊餐巾。餐廳可以購買新的餐巾,每塊餐巾的費用爲 P 分;或者把舊餐巾送到快洗部,洗一塊需 M 天,其費用爲F 分;或者送到慢洗部,洗一塊需N 天,其費用爲SS<F
每天結束時,餐廳必須決定將多少塊髒的餐巾送到快洗部,多少塊餐巾送到慢洗部,以及多少塊保存起來延期送洗。但是每天洗好的餐巾和購買的新餐巾數之和,要滿足當天的需求量。
試設計一個算法爲餐廳合理地安排好n 天中餐巾使用計劃,使總的花費最小。
數據範圍:1n1000

顯然是最小費用最大流
我們考慮拆點,把每一天拆成早上和晚上
源點S 向第i 天早上連一條流量爲inf ,費用爲p 的邊,表示每天早上購買若干條餐巾,每條p
i 天早上向匯點T 連一條流量爲ri ,費用爲0 的邊,表示這一天用了ri 塊餐巾
源點S 向第i 天晚上連一條流量爲ri ,費用爲0 的邊,表示這一天結束後剩下ri 塊髒毛巾
i 天晚上向第i+1 天晚上連一條流量爲inf ,費用爲0 的邊,表示把若干塊髒毛巾留到下一天晚上
i 天晚上向第i+M 天早上連一條流量爲inf ,費用爲F 的邊,表示第i 天晚上把若干塊髒毛巾送到快洗部去洗,過M 天后送回來。
i 天晚上向第i+N 天早上連一條流量爲inf ,費用爲S 的邊,表示第i 天晚上把若干塊髒毛巾送到慢洗部去洗,過N 天后送回來。
然後就是愉快的最小費用最大流啦!
如果有誤在評論區吼一聲哦!
代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll inf=0x7fffffffffffffff;
int n,S,T,l,r,p,df,cf,ds,cs,a[4010],q[4010],inque[4010],pre[4010],tot=1,head[4010],nxt[3200010],to[3200010];
ll ans_flow,ans_cost,d[4010],flw[3200010],cst[3200010];
void add_edge(int u,int v,ll ct,ll fw){
    nxt[++tot]=head[u];
    to[tot]=v;
    flw[tot]=fw;
    cst[tot]=ct;
    head[u]=tot;
    return;
}
void Add_edge(int u,int v,ll ct,ll fw){
    add_edge(u,v,ct,fw);
    add_edge(v,u,-ct,0);
    return;
}
bool spfa(){
    for(int i=1;i<=(n<<1)+1;i++)
        d[i]=inf;
    l=r=d[S]=0;
    q[r++]=S;
    inque[S]=1;
    while(l!=r){
        int u=q[l];
        l=(l+1)%5010;
        inque[u]=0;
        for(int i=head[u];i;i=nxt[i]){
            int v=to[i];
            ll ct=cst[i],fw=flw[i];
            if(fw&&ct+d[u]<d[v]){
                d[v]=d[u]+ct;
                pre[v]=i;
                if(!inque[v]){
                    inque[v]=1;
                    q[r]=v;
                    r=(r+1)%5010;
                }
            }
        }
    }
    if(d[T]==inf)
        return 0;
    ll _flow=inf;
    for(int i=T;i!=S;i=to[pre[i]^1])
        _flow=min(_flow,flw[pre[i]]);
    for(int i=T;i!=S;i=to[pre[i]^1]){
        flw[pre[i]]-=_flow;
        flw[pre[i]^1]+=_flow;
    }
    ans_flow+=_flow;
    ans_cost+=d[T]*_flow;
    return 1;
}
void MCMF(){
    while(spfa());
    return;
}
int main(){
    scanf("%d%d%d%d%d%d",&n,&p,&df,&cf,&ds,&cs);
    S=0;
    T=(n<<1)+1;
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        Add_edge(i,T,0,x);
        Add_edge(S,i+n,0,x);
    }
    for(int i=1;i<=n;i++){
        Add_edge(S,i,p,inf);
        if(i+1<=n)
            Add_edge(i+n,i+n+1,0,inf);
        if(i+df<=n)
            Add_edge(i+n,i+df,cf,inf);
        if(i+ds<=n)
            Add_edge(i+n,i+ds,cs,inf);
    }
    MCMF();
    printf("%lld",ans_cost);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章