网络流与线性规划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; }