zoukankan      html  css  js  c++  java
  • bzoj 1189 二分+最大流判定

    首先我们可以二分一个答案时间T,这样就将最优性问题

    转化为了判定性问题。下面我们考虑对于已知的T的判定

    对于矩阵中所有的空点bfs一次,得出来每个点到门的距离,

    然后连接空点和每个能在t时间内到达的门一条边,容量为1,

    之后连接源和每个空点一条边,容量为1,门连接汇边,容量为t。

    判断最大流是否满流就好了。

    /**************************************************************
        Problem: 1189
        User: BLADEVIL
        Language: Pascal
        Result: Accepted
        Time:24 ms
        Memory:20080 kb
    ****************************************************************/
     
    //By BLADEVIL
    type
        rec                         =record
            x, y                    :longint;
        end;
     
    var
        n, m                        :longint;
        pre, other, len, time       :array[0..1000010] of longint;
        last                        :array[0..1000010] of longint;
        l                           :longint;
        que1                        :array[0..20000] of rec;
        dis                         :array[0..30,0..30] of longint;
        go                          :array[0..2,0..4] of longint;
        num                         :array[0..30,0..30] of longint;
        source, sink                :longint;
        sum                         :longint;
        map                         :array[0..30,0..30] of char;
        que, d                      :array[0..20000] of longint;
         
    function min(a,b:longint):longint;
    begin
        if a>b then min:=b else min:=a;
    end;
         
    procedure connect(a,b,c,d:longint);
    begin
        inc(l);
        pre[l]:=last[a];
        last[a]:=l;
        other[l]:=b;
        len[l]:=c;
        time[l]:=d;
    end;
         
    procedure make(a,b:longint);
    var
        h, t, curx, cury, nx, ny    :longint;
        i, j                        :longint;
        f                           :boolean;
         
    begin
        connect(source,num[a,b],1,0);
        connect(num[a,b],source,0,0);
        fillchar(dis,sizeof(dis),0);
        dis[a,b]:=1; que1[1].x:=a; que1[1].y:=b;
        h:=0; t:=1;
        while h<t do
        begin
            inc(h);
            curx:=que1[h].x; cury:=que1[h].y;
            for i:=1 to 4 do
            begin
                nx:=curx+go[1,i]; ny:=cury+go[2,i];
                if (nx<1) or (nx>n) or (ny<1) or (ny>m) then continue;
                if dis[nx,ny]<>0 then continue;
                if map[nx,ny]='X' then continue;
                inc(t);
                que1[t].x:=nx; que1[t].y:=ny;
                dis[nx,ny]:=dis[curx,cury]+1;
            end;
        end;
        f:=false;
        for i:=1 to n do
            for j:=1 to m do
            if map[i,j]='D' then
                if dis[i,j]<>0 then
                begin
                    f:=true;
                    connect(num[a,b],num[i,j],1,dis[i,j]-1);
                    connect(num[i,j],num[a,b],0,dis[i,j]-1);
                end;
        if not f then
        begin
            writeln('impossible');
            halt;
        end;
    end;
         
    procedure init;
    var
        i, j                        :longint;
    begin
        go[1,1]:=-1; go[2,2]:=1; go[1,3]:=1; go[2,4]:=-1;
        readln(n,m);
        for i:=1 to n do
        begin
            for j:=1 to m do read(map[i,j]);
            readln;
        end;
         
        for i:=1 to n do
            for j:=1 to m do num[i,j]:=(i-1)*m+j;
         
        source:=2*n*m+2; sink:=source+1;
        l:=1;
        for i:=1 to n do
            for j:=1 to m do
                if map[i,j]='.' then
                begin
                    make(i,j);
                    inc(sum);
                end;
                 
        for i:=1 to n do
            for j:=1 to m do
                if map[i,j]='D' then
                begin
                    connect(num[i,j],sink,1,0);
                    connect(sink,num[i,j],0,0);
                end;
    end;
     
    function bfs(up:longint):boolean;
    var
        q, p                        :longint;
        h, t, cur                   :longint;
    begin
        fillchar(d,sizeof(d),0);
        que[1]:=source; h:=0; t:=1; 
        d[source]:=1;
        while h<t do
        begin
            inc(h);
            cur:=que[h];
            q:=last[cur];
            while q<>0 do
            begin
                if (len[q]>0) and (time[q]<=up) then
                begin
                    p:=other[q];
                    if (d[p]=0) then
                    begin
                        inc(t);
                        que[t]:=p;
                        d[p]:=d[cur]+1;
                        if p=sink then exit(true);
                    end;
                end;
                q:=pre[q];
            end;
        end;
        exit(false);
    end;
     
    function dinic(x,flow,up:longint):longint;
    var
        tmp, rest                   :longint;
        q, p                        :longint;
    begin
        rest:=flow;
        if x=sink then exit(flow);
        q:=last[x];
        while q<>0 do
        begin
            p:=other[q];
            if (len[q]>0) and (time[q]<=up) and (rest>0) and (d[x]=d[p]-1) then
            begin
                tmp:=dinic(p,min(len[q],rest),up);
                dec(rest,tmp);
                dec(len[q],tmp);
                inc(len[q xor 1],tmp);
            end;
            q:=pre[q];
        end;
        exit(flow-rest);
    end;
     
    function judge(mid:longint):boolean;
    var
        q                           :longint;
        tot                         :longint;
        i                           :longint;
    begin
        q:=last[sink];
        while q<>0 do
        begin
            len[q]:=0;
            len[q xor 1]:=mid;
            q:=pre[q];
        end;
        tot:=0;
        while bfs(mid) do
            tot:=tot+dinic(source,maxlongint,mid);
        for i:=1 to l do if i mod 2=0 then
        begin
            inc(len[i],len[i xor 1]);
            len[i xor 1]:=0;
        end;
        if tot<sum then exit(false) else exit(true);
    end;
     
    procedure main;
    var
        l, r, mid, ans              :longint;
    begin
        l:=1; r:=2000;
        while l<=r do
        begin
            mid:=(l+r) div 2;
            if judge(mid) then
            begin
                ans:=mid;
                r:=mid-1;
            end else l:=mid+1;
        end;
        writeln(ans);
    end;
     
    begin
        init;
        main;
    end.
  • 相关阅读:
    ARM汇编指令
    Linux系统里如何彻底的清空终端屏幕?
    Linux命令(16)压缩,解压文件
    Linux命令(18)查看当前用户who、whoami、who am i
    Linux命令(17)du 查看文件和目录磁盘使用情况
    Mongodb(3)插入文档,更新文档,删除文档
    Mongodb(2)创建数据库,删除数据库,创建集合,删除集合,显示文档内容
    Mongodb(1)如何存储以及简介
    Linux命令(15)查看系统版本信息
    Python 结巴分词(2)关键字提取
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3500245.html
Copyright © 2011-2022 走看看