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

  除了初始点和目标点之外,剩下的点如果被经过那么就会被交换两次,所以我们将一个点拆成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:
    User: BLADEVIL
    Language: Pascal
    Result: Accepted
    Time: ms
    Memory: kb
****************************************************************/
 
//By BLADEVIL
var
    n, m                        :longint;
    num                         :array[..,..] of longint;
    source, sink                :longint;
    go                          :array[..,..] of longint;
    ans                         :longint;
    last                        :array[..] of longint;
    pre, other, len, cost       :array[..] of longint;
    l                           :longint;
    que, d, father              :array[..] of longint;
    flag                        :array[..] of boolean;
    map                         :array[..,..] 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[,]:=-; go[,]:=; go[,]:=; go[,]:=-;
    go[,]:=-; go[,]:=;
    go[,]:=; go[,]:=;
    go[,]:=; go[,]:=-;
    go[,]:=-; go[,]:=-;
    sum1:=; sum2:=; l:=;
    for i:= to n do
        for j:= to m do num[i,j]:=(i-)*m+j;
     
    source:=n*m*+; sink:=source+;
    for i:= to n do
    begin
        for j:= to m do
        begin
            read(s);
            if s='' then
            begin
                connect(source,num[i,j]+n*m,,);
                connect(num[i,j]+n*m,source,,);
                map[i,j]:=;
                inc(sum1);
            end;
        end;
        readln;
    end;
    for i:= to n do
    begin
        for j:= to m do
        begin  
            read(s);
            if s='' then
            begin
                connect(num[i,j]+n*m,sink,,);
                connect(sink,num[i,j]+n*m,,);
                map[i,j]:=;
                inc(sum2);
            end;
        end;
        readln;
    end;
    if sum1<>sum2 then
    begin
        writeln(-);
        halt;
    end;
    for i:= to n do
    begin
        for j:= to m do
        begin
            read(s);
            key:=ord(s)-;
            if map[i,j]= then
            begin
                connect(num[i,j],num[i,j]+n*m,key div ,);
                connect(num[i,j]+n*m,num[i,j],,);
                connect(num[i,j]+n*m,num[i,j]+*n*m,key div ,);
                connect(num[i,j]+*n*m,num[i,j]+n*m,,);
            end else
            if map[i,j]= then
            begin
                connect(num[i,j],num[i,j]+n*m,key div ,);
                connect(num[i,j]+n*m,num[i,j],,);
                connect(num[i,j]+n*m,num[i,j]+*n*m,(key+) div ,);
                connect(num[i,j]+*n*m,num[i,j]+n*m,,);
            end else
            begin
                connect(num[i,j],num[i,j]+n*m,(key+) div ,);
                connect(num[i,j]+n*m,num[i,j],,);
                connect(num[i,j]+n*m,num[i,j]+*n*m,key div ,);
                connect(num[i,j]+*n*m,num[i,j]+n*m,,);
            end;
        end;
        readln;
    end;
    for i:= to n do
        for j:= to m do
            for k:= to do
            begin
                nx:=i+go[,k];
                ny:=j+go[,k];
                if (nx<) or (nx>n) or (ny<) or (ny>m) then continue;
                connect(num[i,j]+*n*m,num[nx,ny],maxlongint div ,);
                connect(num[nx,ny],num[i,j]+*m*n,,-);
            end;
end;
 
function spfa:boolean;
var
    cur, h, t                   :longint;
    q, p                        :longint;
begin
    filldword(d,sizeof(d) div , maxlongint div );
    d[source]:=;
    h:=; t:=;
    que[]:=source;
    while h<>t do
    begin
        h:=h mod +;
        cur:=que[h];
        flag[cur]:=false;
        q:=last[cur];
        while q<> do
        begin
            if len[q]> 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 +;
                        que[t]:=p;
                        flag[p]:=true;
                    end;
                end;
            end;
            q:=pre[q];
        end;
    end;
    if d[sink]=maxlongint div 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 ];
    end;
    cur:=sink;
    while cur<>source do
    begin
        dec(len[father[cur]],low);
        inc(len[father[cur] xor ],low);
        inc(ans,low*cost[father[cur]]);
        cur:=other[father[cur] xor ];
    end;
end;
 
procedure main;
var
    q                           :longint;
begin
    while spfa do update;
    q:=last[source];
    while q<> do
    begin
        if len[q]> then
        begin
            writeln(-);
            halt;
        end;
        q:=pre[q];
    end;
    writeln(ans);
end;
 
begin
    init;
    main;
end.

bzoj 2668 费用流的更多相关文章

  1. bzoj 3171 费用流

    每个格拆成两个点,出点连能到的点的入点,如果是箭头指向 方向费用就是0,要不就是1,源点连所有出点,所有入点连 汇点,然后费用流 /********************************** ...

  2. bzoj 1449 费用流

    思路:先把没有进行的场次规定双方都为负,对于x胜y负 变为x + 1胜 y - 1 负所需要的代价为 2 * C[ i ] * x  - 2 * D[ i ] * y + C[ i ] + D[ i ...

  3. BZOJ 1061费用流

    思路: 我们可以列出几个不等式 用y0带进去变成等式 下-上 可以消好多东西 我们发现 等式左边的加起来=0 可以把每个方程看成一个点 正->负 连边 跑费用流即可 //By SiriusRen ...

  4. BZOJ 1283 费用流

    思路: 最大费用最大流 i->i+1 连边k 费用0 i->i+m (大于n的时候就连到汇) 连边1 费用a[i] //By SiriusRen #include <queue> ...

  5. bzoj 1070 费用流

    //可以网络流,但是要怎么分配每辆车让谁维修以及维修顺序呢.可以考虑每辆车维修时间对总结果的贡献,把每个修车人拆成n个点共n*m个点, //n辆车连向这n*m个点,流量1,费用k*修车时间,其中k(1 ...

  6. bzoj 2245 费用流

    比较裸 源点连人,每个人连自己的工作,工作连汇,然后因为人的费用是 分度的,且是随工作数非降的,所以我们拆边,源点连到每个人s+1条边 容量是每段的件数,费用是愤怒 /**************** ...

  7. BZOJ 3280 费用流

    思路: 同BZOJ 1221 //By SiriusRen #include <queue> #include <cstdio> #include <cstring> ...

  8. BZOJ 4514 费用流

    思路: 懒得写了 http://blog.csdn.net/werkeytom_ftd/article/details/51277482 //By SiriusRen #include <que ...

  9. BZOJ 2668 [cqoi2012]交换棋子 | 最小费用最大流

    传送门 BZOJ 2668 题解 同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x).中间点mi(x).出点ou(x). 如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, ...

随机推荐

  1. 一步一步构建手机WebApp开发——环境搭建篇

    从2007年,乔布斯带来了第一代Iphone手机,整个移动互联网发生天翻地覆的变化,也同时证明了乔布斯的一句名言:“再一次改变世界”. 在当今的移动互联网,手机App居多,很多App对移动设备的要求也 ...

  2. 配置SSH无密钥登陆(三)

    配置SSH无密钥登陆 (1).关闭防火墙 对每个虚拟机进行如下操作:   su    chkconfig  iptables  off 执行之后重启虚拟机:reboot (2).关闭之后,在maste ...

  3. hibernate和mybatis的之CRUD封装差别

    hibernate和mybatis的之CRUD封装差别 以下讲的是基于MVC三层架构. 由于设计架构的差别,hibernate在实际编程中可以把基础的CRUD封装,比如BaseDao类.其它类只要去继 ...

  4. Alpha项目冲刺(团队作业5)

    团队成员 组 员 学号 朱世杰 211414141 曹晔宁 211306302 一.冲刺(7次 Scrum) [Alpha版本]冲刺阶段--Day 1 [Alpha版本]冲刺阶段--Day 2 [Al ...

  5. beta版本冲刺四

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员:恺琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组 ...

  6. 附录A培训实习生-面向对象基础类和实例(1)

    对象是一个自包含的实体,用一组可识别的特性和行为来标识. 面向对象编程,Object-Oriented Programming,其实就是针对对象进行编程的意思. 类就是具有相同属性和功能的对象的抽象的 ...

  7. Luogu 3435 POI2006OKR-Periods of Words(kmp)

    显然答案应该是Σi-next[next[……next[i]]] (next[next[……next[i]]]>0).递推即可. #include<iostream> #include ...

  8. [NOI2010]能量采集 解题报告

    [NOI2010]能量采集 题目描述 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后,栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起. ...

  9. BZOJ day2_plus

    大半夜的刷b站,好爽啊... 突破十九题 1008105110591088117911911192143218761951196821402242243824562463276128184720

  10. 关于连通性问题的Tarjan算法暂结

    关于基础知识的预备桥和割点.双联通分量.强连通分量,支配树.(并不会支配树) 关于有向图的Tarjan,是在熟悉不过的了,它的主要功能就是求强联通分量,缩个点,但是要注意一下构建新图的时候有可能出现重 ...