您的位置:首页 > 理论基础 > 计算机网络

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

2014-03-24 17:23 411 查看
题目描述 Description

一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s<f 分。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 N 天中餐巾使用计划,使总的花费最小。
编程找出一个最佳餐巾使用计划.

输入描述 Input Description

第 1 行有 6 个正整数 N,p,m,f,n,s。N 是要安排餐巾使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗一块餐巾需要的费用;n 是慢洗部洗一块餐巾需用天数;s 是慢洗部洗一块餐巾需要的费用。接下来的 N 行是餐厅在相继的 N 天里,每天需用的餐巾数。

输出描述 Output Description

将餐厅在相继的 N 天里使用餐巾的最小总花费输出

样例输入 Sample Input

3 10 2 3 3 2

5

6

7

样例输出 Sample Output

145

经典构图

拆点,把每天拆成两个点,一个是入点,流到这里的流表示来源,一个是出点,从这里流出去的点表示去向,入点和出点用Ri和Ci表示,每天的需求用day[i]表示

从s向Ci连容量为day[i]费用为0的边,表示有这么多毛巾用完

从s向Ri连容量为无穷大费用为p的边,表示每天都可以买毛巾

从Ri向t连容量为day[i]费用为0的边,表示每天必须用这么多毛巾

从Ci向Ri+m连容量为无穷费用为f的边,表示第i天用完的毛巾送入快洗部i+m天的时候可以用了,慢洗也一样

从Ri向Ri+1连容量为无穷大费用为0的边,表示第i天没用完,i+1天继续用

const
maxn=800;
maxlongint=100000000;
var
map,w:array[0..maxn*2,0..maxn*2]of longint;
first,next,last:array[0..maxn*maxn*2]of longint;
n,p,k,fk,m,fm,tot,ans:longint;

procedure insert(x,y:longint);
begin
inc(tot);
last[tot]:=y;
next[tot]:=first[x];
first[x]:=tot;
end;

procedure init;
var
i:longint;
begin
read(n,p,k,fk,m,fm);
for i:=1 to n do
begin
read(map[0,i]);
map[i+maxn,n+maxn+1]:=map[0,i];
insert(0,i);
insert(i+maxn,n+maxn+1);
end;
for i:=1 to n-1 do
begin
insert(i,i+1);
insert(i+1,i);
map[i,i+1]:=maxlongint;
end;
for i:=1 to n do
begin
insert(0,i+maxn);
map[0,i+maxn]:=maxlongint;
w[0,i+maxn]:=p;
if i+m<=n then
begin
insert(i,i+m+maxn);
insert(i+m+maxn,i);
map[i,i+m+maxn]:=maxlongint;
w[i,i+m+maxn]:=fm;
w[i+m+maxn,i]:=-fm;
end;
if (k<>m)and(i+k<=n) then
begin
insert(i,i+k+maxn);
insert(i+k+maxn,i);
map[i,i+k+maxn]:=maxlongint;
w[i,i+k+maxn]:=fk;
w[i+k+maxn,i]:=-fk;
end;
end;
end;

var
dis,f,vis:array[0..maxn*2]of longint;
time,flow:longint;

function dfs(x,flow:longint):longint;
var
i,min,d:longint;
begin
if x=n+maxn+1 then
begin
inc(ans,flow*dis[n+maxn+1]);
exit(flow);
end;
vis[x]:=time;
i:=first[x];
dfs:=0;
while i<>0 do
begin
d:=dis[x]+w[x,last[i]]-dis[last[i]];
min:=flow;
if map[x,last[i]]<min then min:=map[x,last[i]];
if (min>0)and(f[last[i]]>d) then f[last[i]]:=d;
if (min>0)and(d=0)and(vis[last[i]]<>time) then
begin
d:=dfs(last[i],min);
inc(dfs,d);
dec(flow,d);
dec(map[x,last[i]],d);
inc(map[last[i],x],d);
end;
if flow=0 then break;
i:=next[i];
end;
end;

procedure work;
var
i,imp:longint;
begin
repeat
inc(time);
for i:=1 to n do
begin
f[i]:=maxlongint;
f[i+maxn]:=maxlongint;
end;
f[0]:=maxlongint;
f[n+maxn+1]:=maxlongint;
inc(flow,dfs(0,maxlongint));
imp:=maxlongint;
for i:=1 to n do
begin
if (vis[i]<>time) and (f[i]<imp) then imp:=f[i];
if (vis[i+maxn]<>time) and (f[i+maxn]<imp) then imp:=f[i+maxn];
end;
if (vis[n+maxn+1]<>time) and (f[n+maxn+1]<imp) then imp:=f[n+maxn+1];
if imp=maxlongint then break;
for i:=1 to n do
begin
if vis[i]<>time then inc(dis[i],imp);
if vis[i+maxn]<>time then inc(dis[i+maxn],imp);
end;
if vis[n+maxn+1]<>time then inc(dis[n+maxn+1],imp);
until false;
write(ans);
end;

begin
init;
work;
end.


zkw费用流
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: