网络流与线性规划24题 之 餐巾计划问题

算法实现题8-10 餐巾计划问题(习题8-21)
«问题描述:
一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同。假设第i天需要ri块餐巾(i=1,
2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为p分;或者把旧餐巾送到快洗部,
洗一块需m天,其费用为f 分;或者送到慢洗部,洗一块需n 天(n>m),其费用为s<f 分。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多
少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好N 天中餐巾使用计划,使总的花费最小。
«编程任务:
编程找出一个最佳餐巾使用计划.
«数据输入:
由文件input.txt提供输入数据。文件第1 行有6 个正整数N,p,m,f,n,s。N 是要安排餐巾
使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗
一块餐巾需要的费用;n是慢洗部洗一块餐巾需用天数;s是慢洗部洗一块餐巾需要的费用。
接下来的N 行是餐厅在相继的N 天里,每天需用的餐巾数。
«结果输出:
程序运行结束时,将餐厅在相继的N 天里使用餐巾的最小总花费输出到文件output.txt
中。
输入文件示例 输出文件示例

input.txt

3 10 2 3 3 2

5
6

7

output.txt

145

【建模方法】
经典构图题。将每一天拆成两个点i, i’,加如下6条边:
(s, i, ri, p)——在第i天可以买至多ri个餐巾,每块p分;
(i, t, ri, 0)——第i天要用ri块餐巾;
(s, i’, ri, 0)——第i天用剩的ri块旧餐巾;
(i’, i+m, ∞, f)——第i天的旧餐巾送到快洗部,每块f分;
(i’, i+n, ∞, s)——第i天的旧餐巾送到慢洗部,每块s分;
(i’, i’+1, ∞, 0)——第i天的旧餐巾可以留到第i+1天再处理;
求一次最小费用流即为结果。(引自《网络流建模汇总》by Edelweiss)

code如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
int N,p,m,f,n,s,S,T,ecnt,ans,first[2100],nxt[1000100];
struct Edge{int u,v,cap,cost;}e[1000100];
bool vis[2100];
int d[2100],q[2100];
void Link(int a,int b,int w,int c)
{
    e[++ecnt].u=a,e[ecnt].v=b,e[ecnt].cap=w,e[ecnt].cost=c;
    nxt[ecnt]=first[a],first[a]=ecnt;
    e[++ecnt].u=b,e[ecnt].v=a,e[ecnt].cap=0,e[ecnt].cost=-c;
    nxt[ecnt]=first[b],first[b]=ecnt;
}
bool spfa()
{
    memset(vis,false,sizeof(vis));
    for(int i=S;i<=T;i++)d[i]=INF;//search for mininum;
    int head=0,tail=1;
    q[0]=T,vis[T]=true,d[T]=0;
    while(head^tail){
        int now=q[head++];
        if(head==2000)head=0;
        for(int i=first[now];i;i=nxt[i])
            if(d[e[i].v]>d[now]-e[i].cost&&e[i^1].cap){
                d[e[i].v]=d[now]+e[i^1].cost;
                if(!vis[e[i].v]){
                    vis[e[i].v]=true;
                    q[tail++]=e[i].v;
                    if(tail==2000)tail=0;
                }
            }
        vis[now]=false;
    }
    return d[S]^INF;
}
int dfs(int x,int f)
{
    vis[x]=true;
    if(!(x^T))return f;
    int used=0,w;
    for(int i=first[x];i;i=nxt[i])
        if(!vis[e[i].v]&&e[i].cap&&d[x]-e[i].cost==d[e[i].v]){
            w=f-used;
            w=dfs(e[i].v,min(e[i].cap,w));
            e[i].cap-=w;e[i^1].cap+=w;
            ans+=w*e[i].cost;
            used+=w;
            if(used==f)return f;
        }
    return used;
}
void zkw()
{
    while(spfa()){
        vis[T]=true;
        while(vis[T]){
            memset(vis,false,sizeof(vis));
            dfs(S,INF);
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d%d",&N,&p,&m,&f,&n,&s);
    S=0,T=N*2+1,ecnt=1;
    for(int i=1;i<=N;i++){
        int x;
        scanf("%d",&x);
        Link(S,i,x,0);
        Link(S,i+N,INF,p);
        Link(i+N,T,x,0);
        if(i+1<=N)Link(i,i+1,INF,0);
        if(i+m<=N)Link(i,i+N+m,INF,f);
        if(i+n<=N)Link(i,i+N+n,INF,s);
    }
    zkw();
    printf("%d\n",ans);
    return 0;
}



 

posted @ 2016-07-15 10:45  keshuqi  阅读(140)  评论(0编辑  收藏  举报