思路

相当神奇的费用流拆点模型
最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法
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. Java基础(basis)-----关键字break、continue、return的区别

       1.break      break只能用于switch语句和循环语句中,跳出当前循环:但是如果是嵌套循环, 则只能跳出当前的这一层循环,只有逐层break才能跳出所有循环 for (int i ...

  2. 基于TCP/IP协议的socket通讯client

    package com.ra.car.utils; import java.io.BufferedReader; import java.io.IOException; import java.io. ...

  3. 【Linux学习一】命令查看与帮助

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 一.Linux执行命令流程:shell->bash(解释器 执行 ...

  4. jQuery图片懒加载插件jquery.lazyload.js使用实例注意事项说明

    jQuery图片懒加载插件jquery.lazyload.js使用实例注意事项说明 jquery.lazyload.js是一个用JavaScript编写的jQuery插件.它可以延迟加载长页面中的图片 ...

  5. php中生成标准uuid(guid)的方法

    );// "}"        return $uuid;    }}echo guid();?>

  6. nfs共享文件搭建

    Linux NFS服务器的安装与配置详解 一.NFS服务简介  NFS是Network  File System(网络文件系统).主要功能是通过网络让不同的服务器之间可以共享文件或者目录.NFS客户端 ...

  7. Kattis之旅——Number Sets

    You start with a sequence of consecutive integers. You want to group them into sets. You are given t ...

  8. STM32硬件IIC (转)

    源: STM32硬件IIC

  9. 基于STM32F4移植W5500官方驱动库ioLibrary_Driver(转)

    源: 基于STM32F4移植W5500官方驱动库ioLibrary_Driver 参考: 基于STM32+W5500 的Ethernet和Internet移植 Upgrade W5500 Throug ...

  10. java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream

    java.lang.ClassNotFoundException: org.apache.commons.io.output.DeferredFileOutputStream at org.apach ...