思路

相当神奇的费用流拆点模型
最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法
S向所有初始是黑色点的入点连cap=1,cost=0的边,最后是黑色点的出点向T连一条cap=1,cost=0的边,然后对应点的出点向它八连通的点的入点连一条cap=INF,cost=1的边,每个点的入点向出点连一条cap=limit,cost=0的边
看起来很靠谱,实际是假的
因为我们刚才的方法没有考虑到一条交换路径的两个端点只交换一次并且路径上其他点都交换了两次(也就是端点和路径上的其他点没有区别)
所以可以拆成三层图。
S向每个初始黑点的mid连边,每个最终黑点的mid向T连边,相邻点连边不变,
然后懒得讲了。。。。

代码

···cpp

include

include

include

include

include

using namespace std;
struct Edge{
int u,v,cap,cost,flow;
};
const int MAXN = 1550;
const int INF = 0x3f3f3f3f;
vector edges;
vector G[MAXN];
int d[MAXN],p[MAXN],a[MAXN],vis[MAXN],s,t,n,m;
queue q;
void addedge(int u,int v,int cap,int cost){
edges.push_back((Edge){u,v,cap,cost,0});
edges.push_back((Edge){v,u,0,-cost,0});
int cnt=edges.size();
G[u].push_back(cnt-2);
G[v].push_back(cnt-1);
}
bool spfa(int &cost,int &flow){
memset(d,0x3f,sizeof(d));
memset(p,0,sizeof(p));
q.push(s);
d[s]=0;
a[s]=INF;
p[s]=0;
vis[s]=true;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=false;
for(int i=0;i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(e.cap>e.flow&&d[x]+e.cost<d[e.v]){
d[e.v]=d[x]+e.cost;
p[e.v]=G[x][i];
a[e.v]=min(a[x],e.cap-e.flow);
if(!vis[e.v]){
vis[e.v]=true;
q.push(e.v);
}
}
}
}
if(d[t]==INF)
return false;
flow+=a[t];
cost+=a[t]d[t];
for(int i=t;i!=s;i=edges[p[i]].u){
edges[p[i]].flow+=a[t];
edges[p[i]^1].flow-=a[t];
}
return true;
}
void MCMF(int &cost,int &flow){
cost=flow=0;
while(spfa(cost,flow));
}
inline int id(int x,int y){
return (x-1)
m+y;
}
char S[50];
int pre_map[30][30],bac_map[30][30];
int main(){
s=MAXN-2;
t=MAXN-3;
int cntb1=0,cntb2=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",S+1);
for(int j=1;j<=m;j++){
if(S[j]=='0'){
cntb1++;
addedge(s,id(i,j)+2nm,1,0);
}
pre_map[i][j]=S[j]-'0';
}
}
for(int i=1;i<=n;i++){
scanf("%s",S+1);
for(int j=1;j<=m;j++){
if(S[j]=='0'){
cntb2++;
addedge(id(i,j)+2nm,t,1,0);
}
bac_map[i][j]=S[j]-'0';
}
}
if(cntb1!=cntb2){
printf("%d\n",-1);
return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(i!=1){//up
addedge(id(i,j)+nm,id(i-1,j),INF,1);
}
if(j!=1){//left
addedge(id(i,j)+n
m,id(i,j-1),INF,1);
}
if(i!=n){//down
addedge(id(i,j)+nm,id(i+1,j),INF,1);
}
if(j!=m){//right
addedge(id(i,j)+n
m,id(i,j+1),INF,1);
}
if(i!=1&&j!=1){//zuoshang
addedge(id(i,j)+nm,id(i-1,j-1),INF,1);
}
if(i!=n&&j!=1){//zuoxia
addedge(id(i,j)+n
m,id(i+1,j-1),INF,1);
}
if(i!=1&&j!=m){//youshang
addedge(id(i,j)+nm,id(i-1,j+1),INF,1);
}
if(i!=n&&j!=m){//youxia
addedge(id(i,j)+n
m,id(i+1,j+1),INF,1);
}
}
for(int i=1;i<=n;i++){
scanf("%s",S+1);
for(int j=1;j<=m;j++){
if(pre_map[i][j]==1&&bac_map[i][j]==0){
addedge(id(i,j),id(i,j)+2nm,(S[j]-'0'+1)/2,0);
addedge(id(i,j)+2nm,id(i,j)+nm,(S[j]-'0')/2,0);
}
if(pre_map[i][j]==0&&bac_map[i][j]==1){
addedge(id(i,j),id(i,j)+2
nm,(S[j]-'0')/2,0);
addedge(id(i,j)+2
nm,id(i,j)+nm,(S[j]-'0'+1)/2,0);
}
if(pre_map[i][j]==bac_map[i][j]){
addedge(id(i,j),id(i,j)+2nm,(S[j]-'0')/2,0);
addedge(id(i,j)+2nm,id(i,j)+n*m,(S[j]-'0')/2,0);
}
}
}
int cost=0,flow=0;
MCMF(cost,flow);
printf("%d\n",cost);
return 0;
}

···

P3159 [CQOI2012]交换棋子的更多相关文章

  1. [bzoj2668] [洛谷P3159] [cqoi2012] 交换棋子

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

  2. 洛谷P3159 [CQOI2012]交换棋子

    巧妙的拆点方式,首先把1看成黑点,0看成空的,几次交换就可以看成一条路径 1)从容量上看,这条路径为1-2-2-2-2-2----2-1 2)从费用上看,这条路径每条边费用都是1 于是用一种巧妙的拆点 ...

  3. BZOJ2668: [cqoi2012]交换棋子

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

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

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

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

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

  6. [cqoi2012]交换棋子

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

  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. BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)

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

随机推荐

  1. linux本地机上传文件到服务器

    最近工作全部切换到了linux环境下,就是吃喝拉撒全在linux下,微信,web端,qq,web端,-------,各种socket编程,网络通讯- 本地linux机从阿里云下载文件

  2. linux 安装 Python

    一. 打开终端,输入:wget https://www.python.org/ftp/python/3.5.0/Python-3.5.0b4.tgz 下载完毕后 输入解压命令:tar –zxvf Py ...

  3. eclipse更换workspace需要重新设置的内容

    .jdk Window-->java-->Installed JREs,新增或修改你所需要的jdk版本,点击需要的jdk-->edit 在Default VM arguments里面 ...

  4. 蒙特卡洛(Monte Carlo)法求定积分

    https://blog.csdn.net/baimafujinji/article/details/53869358

  5. Redis 的 5 个常见应用场景

    前言Redis 是一个强大的内存型存储,具有丰富的数据结构,使其可以应用于很多方面,包括作为数据库.缓存.消息队列等等. 如果你的印象中Redis只是一个 key-value 存储,那就错过了Redi ...

  6. 设计模式之Singleton(单态)(转)

    定义: Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作. 还有, singleton能够被状 ...

  7. STO(Security Token Offering)证券型通证、代币发行介绍

    STO(Security Token Offering)证券型通证.代币发行介绍:STO(Security Token Offering)是一个新的融资概念.通过证券化的通证进行融资.早在2017年年 ...

  8. 洛谷 P1015 回文数

    #include<iostream> #include<cstdio> #include<cmath> #include<string> #includ ...

  9. Java 持久化操作之 --XML

    摘自:http://www.cnblogs.com/lsy131479/p/8728767.html 1)有关XML简介 XML(EXtensible Markup Language)可扩展标记语言 ...

  10. Jquery autocomplete.js输入框联想补全功能

    Jquery autocomplete.js插件下载地址:http://files.cnblogs.com/files/jinzhiming/autocomplete.rar 有两种用法,一种是直接使 ...