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

来源:互联网 发布:shake it of 编辑:程序博客网 时间:2024/05/17 09:31
算法实现题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 0x3f3f3f3fusing 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;}


1 0
原创粉丝点击