思路

相当神奇的费用流拆点模型
最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法
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. html5-超级链接

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  2. webservice 生成客户端代码

    使用 jdk 自带工具 wsimport wsimport -keep http://webservice/url?wsdl

  3. FTL 数字有逗号

    Long i=100000000l; Map model=new Map(); model.put("t",i); 在freemarker中显示为100,000,000 想按原样输 ...

  4. sql server 中后缀为.mdf的文件是干什么用的??

    在微软的SQL Server 2000 数据库有三种类型的文件: 1)主要数据文件(扩展名.mdf是 primary data file 的缩写) 主要数据文件包含数据库的启动信息,并指向数据库中的其 ...

  5. HOG基本原理

    图像识别,图像预处理,HOG算法介绍. 转自: https://blog.csdn.net/gy429476195/article/details/50156813

  6. 20165305 实验四:Android程序设计

    实验内容 基于Android Studio开发简单的Android应用并部署测试; 了解Android.组件.布局管理器的使用: 掌握Android中事件处理机制. Android Studio安装 ...

  7. Linux下实现免密登录

    过程如下: 1.Linux下生成密钥 通过命令”ssh-keygen -t rsa“ 2.1 通过ssh-copy-id的方式 命令: ssh-copy-id -i ~/.ssh/id_rsa.put ...

  8. RocketMQ最佳实战

    RocketMQ 客户端最佳实践 1. Producer最佳实践 发送消息注意事项 1). 一个应用尽可能用一个Topic,消息子类型用tags来标识,tags可以由应用自由设置. 2). 消息发送成 ...

  9. websocket 原理

    自己写一个websocket import socket, hashlib, base64 sock = socket.socket() sock.bind(('127.0.0.1', 9000)) ...

  10. 那些年 Qzone

    那些年转在Qzone里的: 不喊痛,不一定没感觉.不要求,不一定没期待.不落泪,不一定没伤痕.不说话,不一定没心声.沉默,不代表自己没话说.离开,不代表自己很潇洒.快乐,不代表自己没伤心.幸福,不代表 ...