题意
由于省赛的失利(难以理喻的失常),gxg心情十分沉痛—不能为校争光,也辜负了老师的一番陪养。除此以外更多的是郁闷,但gxg知道大学的大门不会因为自己的郁闷而为自己打开,所以一定要振作起来。为了排遣郁闷,gxg开始玩起了智力游戏。
游戏是这样子的:
n个盒子被放成一圈,每个盒子按顺时针编号为1到n,(1<=n<=1000)。每个盒子里都有一些球,且所有盒子里球的总数不超过n。
这些球要按如下的方式转移:每一步可以将一个球从盒子中取出,放入一个相邻的盒子中。目标是使所有的盒子中球的个数都不超过1。
任务
• 从文件d.in中读入盒子的个数和每个盒子中球的个数
• 计算最少的步数是每个盒子中的球的个数不超过1
分析
给你n个盒子,让你进行尽量少的操作去往左和右放,使得每个盒子的个数不超过1。
所以这题的约束条件便是每个盒子不超过1,而附加条件便是操作数最小。
所以我们可以先把图构出来再跑费用流。
如何构图呢?
我们可以从源点向每个盒子连一条容量为当前盒子的球个数,费用为0的边。
而每个盒子向左右连一条容量为maxlongint,费用为1的边。
最后再从每个盒子向汇点连容量为1,费用为0的边。
最后跑一次最小的费用流即可。
var
n,t,i,x,ans,nu:longint;
b,las,nex,f,v,a,dis,re:array[0..10000] of longint;
bz:array[0..10000] of boolean;
procedure insert(x,y,z,k:longint);
begin
inc(nu);b[nu]:=y;nex[nu]:=las[x];las[x]:=nu;f[nu]:=z;v[nu]:=k;
inc(nu);b[nu]:=x;nex[nu]:=las[y];las[y]:=nu;f[nu]:=0;v[nu]:=-k;
end;
function spfa:boolean;
var l,r,now,p:longint;
begin
l:=0;r:=1;fillchar(bz,sizeof(bz),false);fillchar(dis,sizeof(dis),127);dis[0]:=0;bz[0]:=true;a[1]:=0;
while l<r do begin
inc(l);now:=a[l];p:=las[now];
while p<>0 do begin
if (dis[b[p]]>dis[now]+v[p])and(f[p]>0) then begin
dis[b[p]]:=dis[now]+v[p];re[b[p]]:=p;
if not bz[b[p]] then begin inc(r);a[r]:=b[p];bz[b[p]]:=true;end;
end;p:=nex[p];
end;bz[now]:=false;
end;
exit(dis[t]<>dis[10000]);
end;
function min(l,r:longint):longint;
begin
if l<r then exit(l);exit(r);
end;
procedure find;
var sum,x:longint;
begin
x:=t;sum:=maxlongint;
while x<>0 do begin
sum:=min(sum,f[re[x]]);x:=b[re[x] xor 1];
end;x:=t;
while x<>0 do begin
dec(f[re[x]],sum);inc(f[re[x]xor 1],sum);inc(ans,v[re[x]]*sum);
x:=b[re[x] xor 1];
end;
end;
begin
readln(n);
t:=n+1;nu:=1;
insert(1,n,maxlongint,1);
insert(n,1,maxlongint,1);
for i:=1 to n do begin
readln(x);
insert(0,i,x,0);
insert(i,t,1,0);
if i<>n then insert(i,i+1,maxlongint,1);
if i<>1 then insert(i,i-1,maxlongint,1);
end;
while spfa do find;
writeln(ans);
end.