P4013 数字梯形问题

\[QEUES\ I \]

给的是点的容量,要拆点。我们记录一个 \(id[i,j,1/2]\) 代表在 \([i,j]\) 方位上的入点和出点的编号。源点向每一个第一层的入点连一个流量为 \(1\) 费用为 \(0\) 的边。每一层的入点向出点连一个流量为 \(1\) 费用为 \(matrix[i,j]\) (代表这个位置的数值) 的边。每一层的出点往下一层的入点连流量为 \(1\) 费用为 \(0\) 的边。最后一层的出点向源点连一条流量为 \(1\) 费用为 \(0\) 的边。很显然,这样子保证了点用过就用不了的性质切且保证了答案最小。因为我们要答案最大,所以我们可以把所有边的费用变成负数,然后输出 \(-\min cost\)

\[QEUES\ II \]

不能用的性质转化到了边上,我们可以直接把边的那些流量赋值为 \(1\) 费用赋值为 \(matrix[i,j]\)。注意最后一层的点向汇点的边所是可以用很多次的,搞成 \(inf\) 即可。

下面这个图有点错了,我把费用等于编号了。

\[QEUES\ III \]

什么都可以用,直接把除了源点连向第一层的点的边的流量都赋值为 \(inf\)。由于只能有 \(m\) 个路径跑过去所以第一层到源点的边是 \(1\)

注意下面的代码 \(sink\) 是汇点,\(source\) 是用源点。 \(n,m\) 是反的。

// 2018-11-07 一个矩阵最大的边长是 39 啊,所以开 20 会被我自己出的数据卡,所以来提醒大家
Uses math;

var
    from,reach,next,value,cost:array[-1..500010] of longint;
    dis,pre,last,flow:array[-1..50010] of longint;
    matrix:array[-1..41,-1..41] of longint;
    id:array[-1..41,-1..41,1..2] of longint;
    queue:array[-1..500010] of longint;
    cnt:array[-1..50010] of longint;
    vis:array[-1..50010] of boolean;
    n,m,i,j,l,r,x,y,tot,now,node,sink,source,maxflow,mincost:longint;

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
    for i:=1 to n do add(source,id[1,i,1],1,0);
    for i:=1 to m do for j:=1 to n+i-1 do
        begin
            add(id[i,j,1],id[i,j,2],1,-matrix[i,j]);
            add(id[i,j,2],id[i+1,j,1],1,0);
            add(id[i,j,2],id[i+1,j+1,1],1,0);
        end;
    for i:=1 to n+m-1 do add(id[m,i,2],sink,1,0);
end;

procedure Construction_II;
begin
    for i:=1 to n do add(source,id[1,i,1],1,0);
    for i:=1 to m do for j:=1 to n+i-1 do
        begin
            add(id[i,j,1],id[i+1,j,1],1,-matrix[i,j]);
            add(id[i,j,1],id[i+1,j+1,1],1,-matrix[i,j]);
        end;
    for i:=1 to n+m-1 do add(id[m,i,1],sink,maxlongint div 843,-matrix[m,i]);
end;

procedure Construction_III;
begin
    for i:=1 to n do add(source,id[1,i,1],1,0);
    for i:=1 to m do for j:=1 to n+i-1 do
        begin
            add(id[i,j,1],id[i+1,j,1],maxlongint div 843,-matrix[i,j]);
            add(id[i,j,1],id[i+1,j+1,1],maxlongint div 843,-matrix[i,j]);
        end;
    for i:=1 to n+m-1 do add(id[m,i,1],sink,maxlongint div 843,-matrix[m,i]);
end;

begin
    read(n,m);
    for i:=1 to m do for j:=1 to n+i-1 do
        begin
            inc(node,2); id[i,j,1]:=node; id[i,j,2]:=node+1;
            read(matrix[i,j]);
        end;
    source:=1; sink:=node+2;
    Clear; Construction_I; MincostMaxflow; writeln(-mincost);
    Clear; Construction_II; MincostMaxflow; writeln(-mincost);
    Clear; Construction_III; MincostMaxflow; writeln(-mincost);
end.
posted @ 2019-01-25 22:06  _ARFA  阅读(139)  评论(0编辑  收藏  举报