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


题目描述 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天继续用

 

  1 const
  2     maxn=800;
  3 var
  4     map,w:array[0..maxn*2,0..maxn*2]of longint;
  5     first,next,last:array[0..maxn*maxn*2]of longint;
  6     n,p,k,fk,m,fm,tot,ans:longint;
  7 
  8 procedure insert(x,y:longint);
  9 begin
 10     inc(tot);
 11     last[tot]:=y;
 12     next[tot]:=first[x];
 13     first[x]:=tot;
 14 end;
 15 
 16 procedure init;
 17 var
 18     i,j:longint;
 19 begin
 20     read(n,p,k,fk,m,fm);
 21     insert(0,1+maxn);
 22     map[0,1+maxn]:=maxlongint;
 23     w[0,1+maxn]:=p;
 24     for i:=1 to n do
 25       begin
 26         read(map[0,i]);
 27         map[i+maxn,n+maxn+1]:=map[0,i];
 28         insert(0,i);
 29         insert(i+maxn,n+maxn+1);
 30       end;
 31     for i:=1 to n-1 do
 32       begin
 33         insert(i+maxn,i+maxn+1);
 34         insert(i+maxn+1,i+maxn);
 35         map[i+maxn,i+maxn+1]:=maxlongint;
 36       end;
 37     for i:=1 to n do
 38       begin
 39         if i+m<=n then
 40         begin
 41           insert(i,i+m+maxn);
 42           insert(i+m+maxn,i);
 43           map[i,i+m+maxn]:=maxlongint;
 44           w[i,i+m+maxn]:=fm;
 45           w[i+m+maxn,i]:=-fm;
 46         end;
 47         if (k<>m)and(i+k<=n) then
 48         begin
 49           insert(i,i+k+maxn);
 50           insert(i+k+maxn,i);
 51           map[i,i+k+maxn]:=maxlongint;
 52           w[i,i+k+maxn]:=fk;
 53           w[i+k+maxn,i]:=-fk;
 54         end;
 55       end;
 56 end;
 57 
 58 var
 59     d,dis,pre:array[0..maxn*2]of longint;
 60     flag:array[0..maxn*2]of boolean;
 61     head,num,tail:longint;
 62 
 63 function spfa:boolean;
 64 var
 65     i:longint;
 66 begin
 67     head:=1;
 68     tail:=1;
 69     num:=1;
 70     d[1]:=0;
 71     dis[0]:=0;
 72     dis[n+maxn+1]:=maxlongint;
 73     for i:=1 to n do
 74       begin
 75         dis[i]:=maxlongint;
 76         dis[i+maxn]:=maxlongint;
 77       end;
 78     while num>0 do
 79       begin
 80         i:=first[d[head]];
 81         while i<>0 do
 82           begin
 83             if map[d[head],last[i]]>0 then
 84             if dis[last[i]]>dis[d[head]]+w[d[head],last[i]] then
 85             begin
 86               pre[last[i]]:=d[head];
 87               dis[last[i]]:=dis[d[head]]+w[d[head],last[i]];
 88               if flag[last[i]]=false then
 89               begin
 90                 flag[last[i]]:=true;
 91                 tail:=tail mod(n*2+2)+1;
 92                 d[tail]:=last[i];
 93                 inc(num);
 94               end;
 95             end;
 96             i:=next[i];
 97           end;
 98         flag[d[head]]:=false;
 99         head:=head mod (n*2+2)+1;
100         dec(num);
101       end;
102     if dis[n+maxn+1]<>maxlongint then exit(true);
103     exit(false);
104 end;
105 
106 function min(x,y:longint):longint;
107 begin
108     if x<y then exit(x);
109     exit(y);
110 end;
111 
112 procedure work;
113 var
114     i,flow:longint;
115 begin
116     while spfa do
117       begin
118         flow:=maxlongint;
119         i:=n+maxn+1;
120         while i<>0 do
121           begin
122             flow:=min(flow,map[pre[i],i]);
123             i:=pre[i];
124           end;
125         i:=n+maxn+1;
126         inc(ans,flow*dis[n+maxn+1]);
127         while i<>0 do
128           begin
129             dec(map[pre[i],i],flow);
130             inc(map[i,pre[i]],flow);
131             i:=pre[i];
132           end;
133       end;
134     write(ans);
135 end;
136 
137 begin
138     init;
139     work;
140 end.
SPFA费用流

不过spfa跑这种图有点吃力,用zkw就很快了(这个在wikioi上基本是超时,运气好第10个点992ms,用前向星+记录类型时间就差不多是这个的一半,懒得写记录类型了)

  1 const
  2     maxn=800;
  3     maxlongint=100000000;
  4 var
  5     map,w:array[0..maxn*2,0..maxn*2]of longint;
  6     first,next,last:array[0..maxn*maxn*2]of longint;
  7     n,p,k,fk,m,fm,tot,ans:longint;
  8 
  9 procedure insert(x,y:longint);
 10 begin
 11     inc(tot);
 12     last[tot]:=y;
 13     next[tot]:=first[x];
 14     first[x]:=tot;
 15 end;
 16 
 17 procedure init;
 18 var
 19     i:longint;
 20 begin
 21     read(n,p,k,fk,m,fm);
 22     for i:=1 to n do
 23       begin
 24         read(map[0,i]);
 25         map[i+maxn,n+maxn+1]:=map[0,i];
 26         insert(0,i);
 27         insert(i+maxn,n+maxn+1);
 28       end;
 29     for i:=1 to n-1 do
 30       begin
 31         insert(i,i+1);
 32         insert(i+1,i);
 33         map[i,i+1]:=maxlongint;
 34       end;
 35     for i:=1 to n do
 36       begin
 37         insert(0,i+maxn);
 38         map[0,i+maxn]:=maxlongint;
 39         w[0,i+maxn]:=p;
 40         if i+m<=n then
 41         begin
 42           insert(i,i+m+maxn);
 43           insert(i+m+maxn,i);
 44           map[i,i+m+maxn]:=maxlongint;
 45           w[i,i+m+maxn]:=fm;
 46           w[i+m+maxn,i]:=-fm;
 47         end;
 48         if (k<>m)and(i+k<=n) then
 49         begin
 50           insert(i,i+k+maxn);
 51           insert(i+k+maxn,i);
 52           map[i,i+k+maxn]:=maxlongint;
 53           w[i,i+k+maxn]:=fk;
 54           w[i+k+maxn,i]:=-fk;
 55         end;
 56       end;
 57 end;
 58 
 59 var
 60     dis,f,vis:array[0..maxn*2]of longint;
 61     time,flow:longint;
 62 
 63 function dfs(x,flow:longint):longint;
 64 var
 65     i,min,d:longint;
 66 begin
 67     if x=n+maxn+1 then
 68     begin
 69         inc(ans,flow*dis[n+maxn+1]);
 70         exit(flow);
 71     end;
 72     vis[x]:=time;
 73     i:=first[x];
 74     dfs:=0;
 75     while i<>0 do
 76       begin
 77         d:=dis[x]+w[x,last[i]]-dis[last[i]];
 78         min:=flow;
 79         if map[x,last[i]]<min then min:=map[x,last[i]];
 80         if (min>0)and(f[last[i]]>d) then f[last[i]]:=d;
 81         if (min>0)and(d=0)and(vis[last[i]]<>time) then
 82         begin
 83           d:=dfs(last[i],min);
 84           inc(dfs,d);
 85           dec(flow,d);
 86           dec(map[x,last[i]],d);
 87           inc(map[last[i],x],d);
 88         end;
 89         if flow=0 then break;
 90         i:=next[i];
 91       end;
 92 end;
 93 
 94 procedure work;
 95 var
 96     i,imp:longint;
 97 begin
 98     repeat
 99       inc(time);
100       for i:=1 to n do
101         begin
102           f[i]:=maxlongint;
103           f[i+maxn]:=maxlongint;
104         end;
105       f[0]:=maxlongint;
106       f[n+maxn+1]:=maxlongint;
107       inc(flow,dfs(0,maxlongint));
108       imp:=maxlongint;
109       for i:=1 to n do
110         begin
111           if (vis[i]<>time) and (f[i]<imp) then imp:=f[i];
112           if (vis[i+maxn]<>time) and (f[i+maxn]<imp) then imp:=f[i+maxn];
113         end;
114       if (vis[n+maxn+1]<>time) and (f[n+maxn+1]<imp) then imp:=f[n+maxn+1];
115       if imp=maxlongint then break;
116       for i:=1 to n do
117         begin
118           if vis[i]<>time then inc(dis[i],imp);
119           if vis[i+maxn]<>time then inc(dis[i+maxn],imp);
120         end;
121       if vis[n+maxn+1]<>time then inc(dis[n+maxn+1],imp);
122     until false;
123     write(ans);
124 end;
125 
126 begin
127     init;
128     work;
129 end.
zkw费用流

 

转载于:https://www.cnblogs.com/Randolph87/p/3621345.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值