思路

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

    Gradient 3D text 代码区域 /*css */ body { background-color: #272727; } h1 { font-family: "Arial&quo ...

  2. USMART 组件移植到STM32

    USMART是由ALIENTEK开发的一个串口调试助手组件,通过它可以通过串口调试助手,调用程序里面的任何函数并执行,单个函数最多支持10个输入参数,并支持函数返回值显示. USMART支持的参数类型 ...

  3. golang学习笔记18 用go语言编写移动端sdk和app开发gomobile

    golang学习笔记18 用go语言编写移动端sdk和app开发gomobile gomobile的使用-用go语言编写移动端sdk和app开发https://blog.csdn.net/u01249 ...

  4. window、linux安装jdk,excel 导入oracle,WebService,window 端口查看,svn服务安装,oracle用户解锁

    内存泄露分析插件http://download.eclipse.org/mat/1.3/update-site/birt插件http://download.eclipse.org//birt/upda ...

  5. hive 用户行为分析(活跃。启动,留存,回访,新增)的一些经典sql

    很简单的sql 用户分析语句 :只要自定义简单的udf函数 获取统计时间createdatms字段的使用的日历类 add方法 和simpledateformat 将long类型的 定义多个重载方法 获 ...

  6. Cookie,Session,正则表达式

    一.Cookie和Session基础知识 Cookie:客户端本地存储的键值对 Http访问是不记录状态的,所以要借助session和cookie来保存访问状态  当你在浏览网站的时候,WEB 服务器 ...

  7. 判断闰年C语言版

    #include<stdio.h> int isLeap(int year) { // 必须先判断是平年的情况 后判断闰年的情况 == && year%!=) || yea ...

  8. Mysql报错java.sql.SQLException:null,message from server:"Host '27,45,38,132' is not allowed to connect

    Mysql报错java.sql.SQLException:null,message from server:"Host '27,45,38,132' is not allowed to co ...

  9. 标准库 svc—程序及服务控制

    对于程序及服务的控制,本质上而言就是正确的启动,并可控的停止或退出.在go语言中,其实就是程序安全退出.服务控制两个方面.核心在于系统信号获取.Go Concurrency Patterns.以及基本 ...

  10. 使用 select 实现 goroutine 超时

    虽然携程是Go语言中一个新的概念,嗯,但它本质上依然是属于多线程.超时机制是多线程中是一个非常重要的保障程序的鲁棒性的一个措施:错误是很难预估的,在多线程中更为显著,更容易出现难以预料的错误. 一个异 ...