Description

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

Input

第一行包含两个整数nm(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。

Output

输出仅一行,为最小交换总次数。如果无解,输出-1。


写了一个很假的做法

但是居然正解也是这样的??



好吧好吧

那这题也太丧病了


先想一下这道题的基本建模思路,就是把它想象成一些黑点在一张图上流动,如果一个点初始时是黑色就从源点流一个流量一的边,如果遇到一个目标是黑色的点就可以流去汇点

初始版本 1.0 (甚至能得60分)

然后考虑拆两个点

没前途啊

考虑到一个位置上换来一个点然后再换走的话这个位置被换了2次

但是这个模型没法处理啊。。。

优化版本 1.5

拆成3个点!

怎么说呢。。。比1.0还没前途啊

因为如果这个点本来是黑色的但是它的流量是1

那么它就流不过去了。。。

正解 2.0

如果这个点就是黑色的就把2到3的流量改成(流量上限+1)/2不就完了

然后就喜提满分了??


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define MP make_pair
#define TS top().second
#define M 1000001
#define N 50000
//#define gc getchar
using namespace std; priority_queue<pair<int,int> >q;
int uu,a[M],t,n,m,k,ver[M],edge[M],head[N],nex[M],cnt=1,d[N],h[N],c[M],g[N],x,y,z,s,b[N],cur[N],ans,cost,w[M];
void add(int x,int y,int co,int z)
{
ver[++cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=z; c[cnt]=co;
ver[++cnt]=x; nex[cnt]=head[y]; head[y]=cnt; edge[cnt]=0; c[cnt]=-co;
} bool dji()
{
while(q.size()) q.pop();
memset(d,0,sizeof(d)); memset(g,0x3f,sizeof(g)); memset(b,0,sizeof(b));
d[0]=1; g[0]=0; q.push(MP(0,0));
while(q.size())
{
while(q.size() && b[q.TS]) q.pop();
if(!q.size()) break;
int x=q.TS; q.pop(); b[x]=1;
for(int i=head[x];i;i=nex[i])
if(edge[i] && g[ver[i]]>g[x]+c[i]+h[x]-h[ver[i]])
{
g[ver[i]]=g[x]+c[i]+h[x]-h[ver[i]];
d[ver[i]]=d[x]+1;
q.push(MP(-g[ver[i]],ver[i]));
}
}
if(g[t]<0x3f3f3f3f) return 1;
return 0;
} int dinic(int x,int flow)
{
if(x==t || !flow) return flow;
int re=flow, k;
for(int& i=cur[x];i && re;i=nex[i])
if(edge[i] && d[ver[i]]==d[x]+1 && g[ver[i]]==g[x]+c[i]+h[x]-h[ver[i]])
{
k=dinic(ver[i],min(re,edge[i]));
re-=k; edge[i]-=k; edge[i^1]+=k;
if(!k) d[ver[i]]=0;
}
return flow-re;
} int main()
{
scanf("%d%d",&n,&m); t=n*m*3+1;
for(int i=0;i<n;i++)
for(int j=1;j<=m;j++)
{
scanf("%1ld",&k);
if(k) a[i*m+j]=1, uu+=1;
}
for(int i=0;i<n;i++)
for(int j=1;j<=m;j++)
{
scanf("%1ld",&k);
if(k) w[i*m+j]=1, uu-=1;
if(i) add(i*m+j+n*m*2,(i-1)*m+j,1,0x3f3f3f3f);
if(j!=1) add(i*m+j+n*m*2,i*m+j-1,1,0x3f3f3f3f);
if(i && j!=1) add(i*m+j+n*m*2,(i-1)*m+j-1,1,0x3f3f3f3f);
if(i && j!=m) add(i*m+j+n*m*2,(i-1)*m+j+1,1,0x3f3f3f3f);
if(j!=m) add(i*m+j+n*m*2,i*m+j+1,1,0x3f3f3f3f);
if(i!=n-1) add(i*m+j+n*m*2,(i+1)*m+j,1,0x3f3f3f3f);
if(j!=m && i!=n-1) add(i*m+j+n*m*2,(i+1)*m+j+1,1,0x3f3f3f3f);
if(j!=1 && i!=n-1) add(i*m+j+n*m*2,(i+1)*m+j-1,1,0x3f3f3f3f);
}
if(uu!=0){printf("-1"); return 0;}
for(int i=1;i<=n*m;i++)
{
if(w[i]) add(i+n*m,t,0,1);
if(a[i]) add(0,i,0,1);
}
for(int i=0;i<n;i++)
for(int j=1;j<=m;j++)
{
scanf("%1ld",&k);
if(k)add(i*m+j,i*m+j+n*m,0,k);
if(k && (w[i*m+j]||a[i*m+j])) add(i*m+j+n*m,i*m+j+n*m*2,0,(k+1)/2);
else add(i*m+j+n*m,i*m+j+n*m*2,0,k/2);
} while(dji())
{
memcpy(cur,head,sizeof(head)); z=ans;
while(k=dinic(0,0x3f3f3f3f)) ans+=k;
for(int i=1;i<=t;i++) h[i]+=g[i];
cost+=(ans-z)*h[t];
}
printf("%d",cost);
}

2668: [cqoi2012]交换棋子的更多相关文章

  1. BZOJ 2668: [cqoi2012]交换棋子

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1112  Solved: 409[Submit][Status ...

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

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

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

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

  4. BZOJ2668: [cqoi2012]交换棋子

    题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...

  5. [cqoi2012]交换棋子

      2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1334  Solved: 518[Submit][Stat ...

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

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

  7. 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子

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

  8. BZOJ2668:[CQOI2012]交换棋子——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...

  9. P3159 [CQOI2012]交换棋子

    思路 相当神奇的费用流拆点模型 最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法 S向所有初始是黑 ...

随机推荐

  1. Jquery Easy UI初步学习(三)数据增删改

    第二篇只是学了加载用datagrid加载数据,数据的增删改还没有做,今天主要是解决这个问题了. 在做增删改前需要弹出对应窗口,这就需要了解一下EasyUi的弹窗控件. 摘自:http://philoo ...

  2. Apache Spark Exception in thread “main” java.lang.NoClassDefFoundError: scala/collection/GenTraversableOnce$class

    问题: 今天用Maven搭建了一个Spark的Scala项目,运行后遇到下面异常: Apache Spark Exception in thread “main” java.lang.NoClassD ...

  3. Java方法的参数传递方式为: 值传递

    Java方法的参数传递方式为: 值传递 对于基本数据类型作为参数传递时, 是"按值传递", 这点都认识很清楚. 但是, 当对象或者说引用作为参数传递, Java 的参数传递方式是& ...

  4. angular2 引入jquery

    (注:以下命令都是在项目文件夹根目录下运行的,保证下载的文件都在项目的node_modules文件夹里面) 1. 运行  npm install jquery -save 后会发现在package.j ...

  5. 多表批量导出txt及打压缩包下载

     在一些特殊的业务系统中,有些客户查看报表数据时不需要在浏览器上逐一查看,需要在页面端选择要查看的报表名称(可多选),选择条件,然后将所选中的报表批量导出到txt文件中并且要把批量导出的结果文件打 ...

  6. UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-5: ordin al not in range(128)——解决方案备注

    在vim中使用ycm插件时,偶尔会出现: “UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-5: ord ...

  7. Storm一个executor里运行多个task是为了rebalance

    默认情况下下,一个executor运行一个component,即一个task,但有时会指定多个task: 1 builder.setBolt("", new XxBolt()).s ...

  8. MOTT介绍(2)window安装MQTT服务器和client

    MQTT目录: MQTT简单介绍 window安装MQTT服务器和client java模拟MQTT的发布,订阅 window安装MQTT服务器,我这里下载了一个apache-apollo-1.7.1 ...

  9. Mongodb的入门(1)window安装mongodb

    mongodb: Mongodb,分布式文档存储数据库,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案.MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数 ...

  10. Python 应用剖析工具介绍

    [编者按]本文作者为来自 HumanGeo 的工程师 Davis,主要介绍了用于 Python 应用性能分析的几个工具.由国内 ITOM 管理平台 OneAPM 编译呈现. 在 HumanGeo,我们 ...