郁闷的gxg

题意

由于省赛的失利(难以理喻的失常),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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值