P1251 餐巾计划问题
思路上方的大佬讲的很清楚了,当然把出入点改成黑白天是一个不错的技巧。
- 很显然这一天的脏纸巾可以留到明天,也可以留到快洗部和慢洗部。
- 很显然我可以从买,快洗部和慢洗部这三个地方来拿纸巾。
- 也很显然每天会用掉一些纸巾
- 更显然的是这满足流和费用的性质
代码如下:
// luogu-judger-enable-o2
Uses math;
var
from,reach,next,value,cost:array[-1..50010] of longint;
dis,pre,last,flow:array[-1..50010] of int64;
queue:array[-1..50010] of longint;
cnt:array[-1..8100] of longint;
vis:array[-1..8100] of boolean;
time,money:array[1..2] of longint;
n,m,i,j,k,tot,now,node,sink,source:longint;
maxflow,mincost:int64;
procedure add(x,y,sum_1,sum_2:longint);
begin
inc(tot); from[tot]:=x; reach[tot]:=y; value[tot]:=sum_1; cost[tot]:= sum_2; next[tot]:=cnt[x]; cnt[x]:=tot;
inc(tot); from[tot]:=y; reach[tot]:=x; value[tot]:=0 ; cost[tot]:=-sum_2; next[tot]:=cnt[y]; cnt[y]:=tot;
end;
function spfa:boolean;
var head,tail,now,i:longint;
begin
filldword(dis,sizeof(dis) div 4,maxlongint);
filldword(flow,sizeof(flow) div 4,maxlongint);
filldword(vis,sizeof(vis) div 4,0);
head:=1; tail:=1; queue[1]:=source; vis[source]:=True; dis[source]:=0; pre[sink]:=-1;
while head<=tail do
begin
now:=queue[head]; vis[now]:=False; inc(head);
i:=cnt[now];
while i<>-1 do
begin
if (value[i]>0)and(dis[reach[i]]>dis[now]+cost[i]) then
begin
dis[reach[i]]:=dis[now]+cost[i];
pre[reach[i]]:=now;
last[reach[i]]:=i;
flow[reach[i]]:=min(flow[now],value[i]);
if vis[reach[i]]=False then
begin
vis[reach[i]]:=True;
inc(tail); queue[tail]:=reach[i];
end;
end;
i:=next[i];
end;
end;
if pre[sink]=-1 then exit(False); exit(True);
end;
procedure MincostMaxflow;
begin
maxflow:=0; mincost:=0; now:=0;
while (spfa) do
begin
now:=sink;
inc(maxflow,flow[sink]);
inc(mincost,flow[sink]*dis[sink]);
while now<>source do
begin
dec(value[last[now]],flow[sink]);
inc(value[last[now] xor 1],flow[sink]);
now:=pre[now];
end;
end;
end;
procedure Clear;
begin
filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1); tot:=1;
fillchar(value,sizeof(value),0);
fillchar(reach,sizeof(reach),0);
fillchar(cost,sizeof(cost),0);
fillchar(next,sizeof(next),0);
end;
procedure Construction_I;
begin
source:=1; sink:=(n+1) << 1;
for i:=1 to n do begin read(k); add(source,i+1,k,0); add(i+n+1,sink,k,0); end;
read(k,time[1],money[1],time[2],money[2]);
for i:=1 to n do
begin
if i+2<=n+1 then add(i+1,i+2,maxlongint,0);
if i+1+times[1]<=n+1 then add(i+1,i+times[1],maxlongint,money[1]);
if i+1+times[2]<=n+1 then add(i+1,i+times[2],maxlongint,moeny[2]);
add(source,i+n+1,maxlongint,k);
end;
end;
begin
read(n);
Clear; Construction_I; MincostMaxflow; writeln(mincost);
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿