[BZOJ3698]XWW的难题解题报告|上下界网络流|有源汇最大流

XWW是个影响力很大的人,他有很多的追随者。这些追随者都想要加入XWW教成为XWW的教徒。但是这并不容易,需要通过XWW的考核。
XWW给你出了这么一个难题:XWW给你一个N*N的正实数矩阵A,满足XWW性。
称一个N*N的矩阵满足XWW性当且仅当:(1)A[N][N]=0;(2)矩阵中每行的最后一个元素等于该行前N-1个数的和;(3)矩阵中每列的最后一个元素等于该列前N-1个数的和。
现在你要给A中的数进行取整操作(可以是上取整或者下取整),使得最后的A矩阵仍然满足XWW性。同时XWW还要求A中的元素之和尽量大。

  首先很容易看出这是一个带上下界的网络流题...

  源点向代表每一行的点连边,代表每一列的点向汇点连边

  每一行向每一列连边,连的边就如前面无源汇可行流一样

  然后由于求的是最大流,二分答案

  每次从t→s连一条下限为mid的边

  

  问题来了..最后要输出的和最终的mid有什么关系呢...

  我们考虑这张图上的流量代表什么

  我们连的边代表的刚开始没有考虑下限的边所以认为是波动的数值

  然而实际上很简单就是每个格子的数值

  最后输出的答案是整张图的数值

  每个点在自己位置、行末和列末各统计一次

  所以乘上3输出就可以了

  

  因为INF设得过小WA了两次...

program zoj2314;
const maxn = 2100;maxm = 800010;INF = 100000007;
var fa,next,ter,w,rec,flow:array[-1..maxm]of longint;
    link,dis,opt,inp:array[-1..maxn]of longint;
    vis:array[-1..maxn]of boolean;
    n,m,e,tt,test,i,s,t,x,y,l,r,j,mid,sum,lx,rx,ans:longint;
    a:array[-1..maxn,-1..maxn]of extended;

function min(a,b:longint):longint;
begin
        if a<b then exit(a) else exit(b);
end;

function spfa:boolean;
var head,tail,x,j:longint;
begin
    fillchar(vis,sizeof(vis),true);
    fillchar(dis,sizeof(dis),63);
    head:=0;tail:=1;opt[1]:=s;vis[s]:=false;dis[s]:=0;
    while head<>tail do
    begin
        head:=(head+1) mod maxn;
        x:=opt[head];j:=link[x];
        while j<>0 do
        begin
            if (dis[x]+1<dis[ter[j]])and(w[j]>0) then
            begin
                dis[ter[j]]:=dis[x]+1;
                if vis[ter[j]] then
                begin
                    vis[ter[j]]:=false;
                    tail:=(tail+1) mod maxn;
                    opt[tail]:=ter[j];
                end;
            end;
            j:=next[j];
        end;
        vis[x]:=true;
    end;
    if dis[t]<>dis[t+1] then exit(true) else exit(false);
end;

function dfs(p,sum:longint):longint;
var tem,j,x:longint;
begin
    tem:=0;
    if p=t then exit(sum);
    j:=link[p];
    while j<>0 do
     begin
        if (dis[ter[j]]=dis[p]+1)and(w[j]>0) then
        begin
            x:=dfs(ter[j],min(sum-tem,w[j]));
            inc(tem,x);dec(w[j],x);inc(w[rec[j]],x);
            if rec[j]=j+1 then inc(flow[fa[j]],x) else dec(flow[fa[rec[j]]],x);
            if tem=sum then exit(sum);
        end;
        j:=next[j];
    end;
    exit(tem);
end;

procedure add(x,y,z:longint);
begin
    inc(e);ter[e]:=y;next[e]:=link[x];link[x]:=e;w[e]:=z;rec[e]:=e+1;
    inc(e);ter[e]:=x;next[e]:=link[y];link[y]:=e;w[e]:=0;rec[e]:=e-1;
end;

function Jud:boolean;
var j:longint;
begin
    j:=link[s];
    while j<>0 do
    begin
        if w[j]>0 then exit(false);
        j:=next[j];
    end;
    exit(true);
end;

function Solve:boolean;
var i,sum:longint;
begin
        sum:=0;
    while spfa do inc(sum,dfs(s,1000000007));
    if (not Jud) then exit(false) else exit(true);
end;

begin
    readln(n);ans:=0;
    for i:=1 to n do
    begin
        for j:=1 to n do begin read(a[i,j]);inc(ans,trunc(a[i,j]));end;
        readln;
    end;
    Lx:=0;Rx:=10000000007;sum:=-1;
    while Lx<=Rx do
    begin
        mid:=(Lx+Rx) >> 1;
        fillchar(next,sizeof(next),0);
        fillchar(link,sizeof(link),0);
        fillchar(inp,sizeof(inp),0);
        e:=0;s:=0 ;t:=2*n+1;
        for i:=1 to n-1 do
        begin
            l:=trunc(a[i,n]);
            if a[i,n]<>l then add(s,i,1);
            dec(inp[s],l);inc(inp[i],l);

            l:=trunc(a[n,i]);
            if a[n,i]<>l then add(n+i,t,1);
            dec(inp[n+i],l);inc(inp[t],l);
        end;
        for i:=1 to n-1 do
            for j:=1 to n-1 do
            begin
                l:=trunc(a[i,j]);
                if a[i,j]<>l then add(i,n+j,1);
                dec(inp[i],l);inc(inp[n+j],l);
            end;
        add(t,s,INF);
                inc(inp[s],mid);dec(inp[t],mid);
        dec(s);inc(t);
        for i:=s+1 to t-1 do
        if inp[i]>0 then add(s,i,inp[i]) else
        if inp[i]<0 then add(i,t,-inp[i]);
        if Solve then begin sum:=mid;Lx:=mid+1 end else Rx:=mid-1;
    end;
        writeln(sum*3);
end.

  

原文地址:https://www.cnblogs.com/mjy0724/p/4466568.html