• [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.

      

  • 相关阅读:
    asp.net mvc 学习
    ms sqlserver 清除数据库日志脚本
    DB、ETL、DW、OLAP、DM、BI关系结构图
    日期维度(周一为每周第一天)
    关于C#操作Excel,复制Sheet的记录
    ms sqlserver 登录失败 错误:4064
    通过sqlserver sa密码修改windows操作系统密码
    ssas 为绑定指定的大小太小,导致一个或多个列值被截断
    ExpandoObject的使用
    【慕课网实战】Spark Streaming实时流处理项目实战笔记三之铭文升级版
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4466568.html
Copyright © 2020-2023  润新知