线性规划与网络流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跑这种图有点吃力,用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.