博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 2668 费用流
阅读量:5934 次
发布时间:2019-06-19

本文共 6377 字,大约阅读时间需要 21 分钟。

  我们可以把初始状态转化为目标状态这一约束转化为将黑子移动到目标状态所需要的最少步数。

  除了初始点和目标点之外,剩下的点如果被经过那么就会被交换两次,所以我们将一个点拆成3个点,a,b,c,新建附加源点source汇点sink。设每个点的交换次数为num[i],那么这个点的交换次数如果是奇数其实是没用的,那么我们连接(a,b,num[i] div 2,0),(b,c,num[i] div 2,0),这样代表这个点一共可以被经过num[i] div 2次,那么对于起始点和终点来说,因为不用被经过,所以原来是奇数的话可以走num[i] div 2+1次,所以(a,b,(num[i]+1) div 2,0),(b,c,(num[i]+1) div 2)。对于两个相邻的点(八连通)连接(ci,aj,inf,1)代表随意经过(每个点的经过次数在拆的点内被限制了,这里不用限制)1次需要1的代价。再连接每个初始状态上的黑点(source,b,1,0),连接每个目标状态上的黑点(b,sink,1,0),代表出发点。

  需要注意的细节是如果一个点目标状态和初始状态相同,那么会出现这样一种情况:source连接b,b连接sink,然后着两条边可以相当于没有,但是a连b,b连c的流量是(num[i]+1) div 2。这代表原来+1是因为到这个点之后停止,不需要再流出(经过),所以奇数的话可以多走一次。现在这个点因为源汇的直接连接使得这个点和普通路径上的点相同,那么就不应该+1,所以我们可以处理初始状态和目标状态上的相同的点,直接不考虑,连接的流量也是(num[i]) div 2。还有一种处理方法就是对于初始状态上的点连接(a,b,num[i] div 2,0),(b,c,(num[i]+1) div 2)目标状态上的点连接(a,b,(num[i]+1) div 2,0),(b,c,num[i] div 2)分别代表可以多进入(出去)一次,这一次是直接从source(sink)流入(流出)的。这两种方法都可以解决这一问题。

  对于无解,有两种情况,第一个是初始状态目标状态上的黑点个数不同,第二种情况是没有达到满流,代表不是所有点都流到目标状态,特判就行了。

/**************************************************************    Problem: 2668    User: BLADEVIL    Language: Pascal    Result: Accepted    Time:48 ms    Memory:6516 kb****************************************************************/ //By BLADEVILvar    n, m                        :longint;    num                         :array[0..30,0..30] of longint;    source, sink                :longint;    go                          :array[0..2,0..8] of longint;    ans                         :longint;    last                        :array[0..2010] of longint;    pre, other, len, cost       :array[0..400010] of longint;    l                           :longint;    que, d, father              :array[0..2010] of longint;    flag                        :array[0..2010] of boolean;    map                         :array[0..30,0..30] 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;    cost[l]:=d;end;     procedure init;var    i, j, k                     :longint;    s                           :char;    sum1, sum2                  :longint;    key                         :longint;    nx, ny                      :longint;     begin    readln(n,m);    go[1,1]:=-1; go[2,2]:=1; go[1,3]:=1; go[2,4]:=-1;    go[1,5]:=-1; go[2,5]:=1;    go[1,6]:=1; go[2,6]:=1;    go[1,7]:=1; go[2,7]:=-1;    go[1,8]:=-1; go[2,8]:=-1;    sum1:=0; sum2:=0; l:=1;    for i:=1 to n do        for j:=1 to m do num[i,j]:=(i-1)*m+j;         source:=n*m*3+2; sink:=source+1;    for i:=1 to n do    begin        for j:=1 to m do        begin            read(s);            if s='1' then            begin                connect(source,num[i,j]+n*m,1,0);                connect(num[i,j]+n*m,source,0,0);                map[i,j]:=1;                inc(sum1);            end;        end;        readln;    end;    for i:=1 to n do    begin        for j:=1 to m do        begin              read(s);            if s='1' then            begin                connect(num[i,j]+n*m,sink,1,0);                connect(sink,num[i,j]+n*m,0,0);                map[i,j]:=2;                inc(sum2);            end;        end;        readln;    end;    if sum1<>sum2 then    begin        writeln(-1);        halt;    end;    for i:=1 to n do    begin        for j:=1 to m do        begin            read(s);            key:=ord(s)-48;            if map[i,j]=0 then            begin                connect(num[i,j],num[i,j]+n*m,key div 2,0);                connect(num[i,j]+n*m,num[i,j],0,0);                connect(num[i,j]+n*m,num[i,j]+2*n*m,key div 2,0);                connect(num[i,j]+2*n*m,num[i,j]+n*m,0,0);            end else            if map[i,j]=1 then            begin                connect(num[i,j],num[i,j]+n*m,key div 2,0);                connect(num[i,j]+n*m,num[i,j],0,0);                connect(num[i,j]+n*m,num[i,j]+2*n*m,(key+1) div 2,0);                connect(num[i,j]+2*n*m,num[i,j]+n*m,0,0);            end else            begin                connect(num[i,j],num[i,j]+n*m,(key+1) div 2,0);                connect(num[i,j]+n*m,num[i,j],0,0);                connect(num[i,j]+n*m,num[i,j]+2*n*m,key div 2,0);                connect(num[i,j]+2*n*m,num[i,j]+n*m,0,0);            end;        end;        readln;    end;    for i:=1 to n do        for j:=1 to m do            for k:=1 to 8 do            begin                nx:=i+go[1,k];                ny:=j+go[2,k];                if (nx<1) or (nx>n) or (ny<1) or (ny>m) then continue;                connect(num[i,j]+2*n*m,num[nx,ny],maxlongint div 10,1);                connect(num[nx,ny],num[i,j]+2*m*n,0,-1);            end;end; function spfa:boolean;var    cur, h, t                   :longint;    q, p                        :longint;begin    filldword(d,sizeof(d) div 4, maxlongint div 10);    d[source]:=0;     h:=0; t:=1;    que[1]:=source;    while h<>t do    begin        h:=h mod 2000+1;        cur:=que[h];        flag[cur]:=false;        q:=last[cur];        while q<>0 do        begin            if len[q]>0 then            begin                p:=other[q];                if d[p]>d[cur]+cost[q] then                begin                    d[p]:=d[cur]+cost[q];                    father[p]:=q;                    if not flag[p] then                    begin                        t:=t mod 2000+1;                        que[t]:=p;                        flag[p]:=true;                    end;                end;            end;            q:=pre[q];        end;    end;    if d[sink]=maxlongint div 10 then exit(false) else exit(true);end; procedure update;var    low, cur                    :longint;begin    cur:=sink;    low:=maxlongint;    while cur<>source do    begin        low:=min(low,len[father[cur]]);        cur:=other[father[cur] xor 1];    end;    cur:=sink;    while cur<>source do    begin        dec(len[father[cur]],low);        inc(len[father[cur] xor 1],low);        inc(ans,low*cost[father[cur]]);        cur:=other[father[cur] xor 1];    end;end; procedure main;var    q                           :longint;begin    while spfa do update;    q:=last[source];    while q<>0 do    begin        if len[q]>0 then        begin            writeln(-1);            halt;        end;        q:=pre[q];    end;    writeln(ans);end; begin    init;    main;end.

 

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

你可能感兴趣的文章
dubbo学习笔记四(异步调用)
查看>>
语言代码表
查看>>
IOS数据存储-NSUserDefaults
查看>>
NDK 编译问题 总结
查看>>
复习日记-SQL+连接池
查看>>
hdu 1007 Quoit Design
查看>>
织梦(dedecms)如何清空全部文章和删除后新增文章id号归1的方法
查看>>
认识EasyUI——DataGrid的onClickRow事件
查看>>
Android Studio的使用(四)--生成Get、Set方法
查看>>
删除底部"自豪地采用 WordPress"
查看>>
i897刷机原理分析
查看>>
第二次作业
查看>>
JS判断IE浏览器的最简短方法
查看>>
SCAU 2018 初出茅庐 题解
查看>>
Python 正则表达式爬取浏览目录
查看>>
Spring Boot脚手架
查看>>
python 多线程编程之进程和线程基础概念
查看>>
(一)cacti的原理
查看>>
基与维数
查看>>
BZOJ 3295 [Cqoi2011]动态逆序对 ——CDQ分治
查看>>