题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668

题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与m[i,j]次交换。

思路: 我们将1看做要移动的数字,将0看做空白。那么若1在始末状态个数不同则无解;如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0。将每个格子拆为为个点p0,p1,p2:

(1)若格子初始为1,则连边:<s,p0,1,0>,<p1,p0,m[i][j]/2,0)>,<p0,p2,(m[i][j]+1)/2,0>;

(2)若格子末状态为0,则连边:<p0,t,1,0>,<p1,p0,(m[i][j]+1)/2,0>,<p0,p2,m[i][j]/2,0>;

(3)始末都是空白,则连边:<p1,p0,m[i][j]/2,0>,<p0,p2,m[i][j]/2,0>;

(4)相邻格子x和y连边<px2,py1,INF,0>。

struct node
{
    int u,v,next,cost,cap;
};

node edges[N];
int head[N],e;

void add(int u,int v,int cap,int cost)
{
    edges[e].u=u;
    edges[e].v=v;
    edges[e].cap=cap;
    edges[e].cost=cost;
    edges[e].next=head[u];
    head[u]=e++;
}

void Add(int u,int v,int cap,int cost)
{
    add(u,v,cap,cost);
    add(v,u,0,-cost);
}

int pre[N],F[N],C[N],visit[N];

int SPFA(int s,int t,int n)
{
    int i;
    for(i=0;i<=n;i++) F[i]=0,C[i]=INF,visit[i]=0;
    queue<int> Q;
    Q.push(s); F[s]=INF; C[s]=0;
    int u,v,cost,cap;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();

        visit[u]=0;
        for(i=head[u];i!=-1;i=edges[i].next)
        {
            if(edges[i].cap>0)
            {
                v=edges[i].v;
                cost=edges[i].cost;
                cap=edges[i].cap;
                if(C[v]>C[u]+cost)
                {
                    C[v]=C[u]+cost;
                    F[v]=min(F[u],cap);
                    pre[v]=i;
                    if(!visit[v]) visit[v]=1,Q.push(v);
                }
            }
        }
    }
    return F[t];
}

char a[25][25],b[25][25],c[25][25];
int d[25][25][3];
int dx[]={-1,-1,-1,0,1,1,1,0};
int dy[]={-1,0,1,1,1,0,-1,-1};
int n,m,s,t,cnt;
int ans;

int MCMF(int s,int t,int n)
{
    int i,x,temp,M=0;
    while(temp=SPFA(s,t,n))
    {
        M+=temp;
        for(i=t;i!=s;i=edges[pre[i]].u)
        {
            x=pre[i];
            ans+=edges[x].cost*temp;
            edges[x].cap-=temp;
            edges[x^1].cap+=temp;
        }
    }
    return M==cnt;
}

int main()
{
    RD(n,m);
    int i,j;
    FOR1(i,n) RD(a[i]+1);
    FOR1(i,n) RD(b[i]+1);
    FOR1(i,n) RD(c[i]+1);
    int k=0;
    FOR1(i,n) FOR1(j,m)
    {
        a[i][j]-='0';
        b[i][j]-='0';
        c[i][j]-='0';
        d[i][j][0]=++k;
        d[i][j][1]=++k;
        d[i][j][2]=++k;
        if(a[i][j]&&b[i][j]) a[i][j]=0,b[i][j]=0;
    }
    s=0; t=++k;
    clr(head,-1);
    cnt=0;
    int x,y,p=0;
    FOR1(i,n) FOR1(j,m)
    {
        if(a[i][j])
        {
            cnt++;
            Add(s,d[i][j][0],1,0);
            Add(d[i][j][1],d[i][j][0],c[i][j]/2,0);
            Add(d[i][j][0],d[i][j][2],(c[i][j]+1)/2,0);
        }
        else if(b[i][j])
        {
            p++;
            Add(d[i][j][0],t,1,0);
            Add(d[i][j][1],d[i][j][0],(c[i][j]+1)/2,0);
            Add(d[i][j][0],d[i][j][2],c[i][j]/2,0);
        }
        else
        {
            Add(d[i][j][1],d[i][j][0],c[i][j]/2,0);
            Add(d[i][j][0],d[i][j][2],c[i][j]/2,0);
        }
        FOR0(k,8)
        {
            x=i+dx[k];
            y=j+dy[k];
            if(x>=1&&x<=n&&y>=1&&y<=m)
            {
                Add(d[i][j][2],d[x][y][1],INF,1);
            }
        }
    }
    if(cnt!=p||!MCMF(s,t,t+1)) puts("-1");
    else PR(ans);
}

BZOJ 2668 交换棋子(费用流)的更多相关文章

  1. 【BZOJ2668】[cqoi2012]交换棋子 费用流

    [BZOJ2668][cqoi2012]交换棋子 Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列 ...

  2. BZOJ2668: [cqoi2012]交换棋子(费用流)

    Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...

  3. [BZOJ 2668] 交换棋子

    Link: BZOJ 2668 传送门 Solution: 重点在于对于每条转移路径:首尾算一次,中间节点算两次 可以一点拆三点,将原流量拆成入流量和出流量 但其实也可以就拆两点,分前后是否是一首尾点 ...

  4. BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)

    题目链接 首先黑白棋子的交换等价于黑棋子在白格子图上移动,都到达指定位置. 在这假设我们知道这题用网络流做. 那么黑棋到指定位置就是一条路径,考虑怎么用流模拟出这条路径. 我们发现除了路径的起点和终点 ...

  5. [CQOI2012] 交换棋子 - 费用流

    有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Solution 一个点拆三份,入点,主点 ...

  6. [CQOI2012][bzoj2668] 交换棋子 [费用流]

    题面 传送门 思路 抖机灵 一开始看到这题我以为是棋盘模型-_-|| 然而现实是骨感的 后来我尝试使用插头dp来交换,然后又惨死 最后我不得不把目光转向那个总能化腐朽为神奇的算法:网络流 思维 我们要 ...

  7. [bzoj 1449] 球队收益(费用流)

    [bzoj 1449] 球队收益(费用流) Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 1 ...

  8. BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)

    BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...

  9. bzoj 1070: [SCOI2007]修车 费用流

    1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2785  Solved: 1110[Submit][Status] ...

随机推荐

  1. 夺命雷公狗---TP商城----TP之配置环境---1

    下载到tp3.2.3版本后架设到自己的wamp环境下,然后配置虚拟主机,完事后直接开工 环境下创建一个文件夹,然后里面存放这这两个文件即可开始新的旅途了 这里完了,下一步就开始配置index.php文 ...

  2. 夺命雷公狗jquery---5可见选择器

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. zw版_Halcon图像交换、数据格式、以及超级简单实用的DIY全内存计算.TXT

    zw版_Halcon图像交换.数据格式.以及超级简单实用的DIY全内存计算.TXT Halcon由于效率和其他原因,内部图像采用了很多自有格式,提高运行速度,但在数据交换方面非常麻烦. 特别是基于co ...

  4. 解析php mysql 事务处理回滚操作

    论坛扣币项目中,用户支付论坛币的时候如果突然断网.电脑死机.停电.等其它自然灾害时,导致本次交易没有成功(即用户的币已经扣掉了,但是服务器数据库中没有消费记录等其它情况),这种情况应该怎么样进行处理呢 ...

  5. 对EV-Globe5.0资源体系的简单理解

           如果直接从OpenGL或DirectX底层做起的话,根本就不存在资源管理这一个思想.所谓的资源,就是说内容要从文件读取为我所用的那些文件,所以我们看到的更多的是模型.骨骼.材质.着色器. ...

  6. JeeSite开发笔记

    开发流程笔记: http://m.blog.csdn.net/article/details?id=51251619

  7. JVM学习笔记(二)------Java代码编译和执行的整个过程【转】

    转自:http://blog.csdn.net/cutesource/article/details/5904542 版权声明:本文为博主原创文章,未经博主允许不得转载. Java代码编译是由Java ...

  8. Linux下资源利用率监测利器—nmon使用

    最近接了一个任务,就是测试公司服务器的资源利用率,这样对每种业务平时所占资源有了大体的了解,进而为下一步的虚拟化做准备.找了很多开源的工具,但都不理想,有的安装很复杂,需要联网(而我们的服务器很多都不 ...

  9. PHP将XML数据转换为数组

    <?php $s=join(,file('httpapi.elong.comxmlv2.0hotelcn0132701501.xml')); $result = xml_to_array($s) ...

  10. HDU 3966:Aragorn's Story(树链剖分)

    http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意:有n个点n-1条边,每个点有一个权值,有两种操作:询问一个点上权值是多少和修改u到v这条链上的权值. ...