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 hdo
    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 hdo
    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 totthen 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.

 

转载于:https://www.cnblogs.com/BLADEVIL/p/3500245.html

你可能感兴趣的:(bzoj 1189 二分+最大流判定)