Description

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

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

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

Sample Input
3 3
110
000
001
000
110
100
222
222
222

Sample Output
4

分析:
题面让人觉得很奇怪
实际上我们可以看做只有黑棋子,这样就好处理多了

说实话,这道题的建图是我见过的最zz的
显然初始状态和最终状态该位置都是黑棋时,
这个黑棋是没有必要移动的,对答案没有贡献
所以我们就可以把ta变成白棋

题目的限制不是在棋子上,而是在格子上
我们把每个格子拆成三个点a,b,c

(1)格子的初始状态是1,连接(s,a,1,0),(b,a,m[i][j]/2,0),(a,c,(m[i][j]+1)/2,0)
(2)格子末状态是1,连接(a,t,1,0),(b,a,(m[i][j]+1)/2,0),(a,c,m[i][j]/2,0)
(3)始末都是0,连接(b,a,m[i][j]/2,0),(a,c,m[i][j]/2,0)
(4)相邻格子x,y,连接(xc,yb,INF,1)

解释
对于一次交换,会使用相邻两个格子各一次,一共会使用两次,
所以我们将边权除以二
对于初始黑子在的点,与末尾黑子在的点,
其实对于这个黑子只用交换一次,所以只会使用1的流量,
所以我们把ta的边权令为(m[i][j]+1)/2,这个细节比较重要

附测试样例及图
input
2 2
10
01
01
10
11
11

output
2

tip

发现自己的spfa都写不好了

注意所谓的相邻格子包括对角线

在获取点的编号的时候,get函数中n和m不要弄混了
手残党。。。STO

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>using namespace std;const int INF=0x33333333;
const int N=50010;
int st[N],tot=-1,s,t;
struct node{int x,y,v,c,nxt;
};
node way[N<<2];
int pre[N],dis[N],q[N],tou,wei;
bool p[N];
int mp[100][100],num[100][100],n,m;int get(int x,int y){return (x-1)*m+y;}void add(int u,int w,int v,int cc)
{tot++;way[tot].x=u;way[tot].y=w;way[tot].v=v;way[tot].c=cc;way[tot].nxt=st[u];st[u]=tot;tot++;way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].c=-cc;way[tot].nxt=st[w];st[w]=tot;
}int spfa(int s,int t)
{memset(dis,0x33,sizeof(dis));memset(pre,-1,sizeof(pre));memset(p,1,sizeof(p));wei=tou=0;q[++wei]=s;dis[s]=0;p[s]=0;do{int r=q[++tou];for (int i=st[r];i!=-1;i=way[i].nxt)if (way[i].v&&way[i].c+dis[r]<dis[way[i].y]){dis[way[i].y]=dis[r]+way[i].c;pre[way[i].y]=i;if (p[way[i].y]){q[++wei]=way[i].y;p[way[i].y]=0;} }p[r]=1;}while (tou<wei);return dis[t]!=INF;
}void doit()
{int ans=0;while (spfa(s,t)){int sum=INF;for (int i=t;i!=s;i=way[pre[i]].x)sum=min(sum,way[pre[i]].v);   //pre[i]ans+=sum*dis[t];for (int i=t;i!=s;i=way[pre[i]].x)way[pre[i]].v-=sum,way[pre[i]^1].v+=sum;}printf("%d",ans);
}void lianbian()
{int i,j;s=0; t=n*m*3+1;for (i=1;i<=n;i++)for (j=1;j<=m;j++){if (mp[i][j]==1){add(s,get(i,j),1,0);add(get(i,j)+n*m,get(i,j),num[i][j]/2,0);add(get(i,j),get(i,j)+n*m*2,(num[i][j]+1)/2,0);}else if (mp[i][j]==2){add(get(i,j),t,1,0);add(get(i,j)+n*m,get(i,j),(num[i][j]+1)/2,0);add(get(i,j),get(i,j)+n*m*2,num[i][j]/2,0);}else{add(get(i,j)+n*m,get(i,j),num[i][j]/2,0);add(get(i,j),get(i,j)+n*m*2,num[i][j]/2,0);}if (i+1<=n) add(get(i,j)+n*m*2,get(i+1,j)+n*m,INF,1);if (j+1<=m) add(get(i,j)+n*m*2,get(i,j+1)+n*m,INF,1);if (i-1>0) add(get(i,j)+n*m*2,get(i-1,j)+n*m,INF,1);if (j-1>0) add(get(i,j)+n*m*2,get(i,j-1)+n*m,INF,1);if (i+1<=n&&j+1<=m) add(get(i,j)+n*m*2,get(i+1,j+1)+n*m,INF,1);if (i-1>0&&j-1>0) add(get(i,j)+n*m*2,get(i-1,j-1)+n*m,INF,1);if (i+1<=n&&j-1>0) add(get(i,j)+n*m*2,get(i+1,j-1)+n*m,INF,1);if (i-1>0&&j+1<=m) add(get(i,j)+n*m*2,get(i-1,j+1)+n*m,INF,1);}
}int main()
{scanf("%d%d",&n,&m);memset(st,-1,sizeof(st));char ch[30];int cnt=0;for (int i=1;i<=n;i++){scanf("%s",&ch);for (int j=0;j<m;j++){mp[i][j+1]=ch[j]-'0';if (ch[j]-'0'==1) cnt++;}}for (int i=1;i<=n;i++){scanf("%s",&ch);for (int j=0;j<m;j++){int x=ch[j]-'0';if (x) cnt--;if (mp[i][j+1]==1&&x==0) mp[i][j+1]=1;else if (mp[i][j+1]==0&&x==1) mp[i][j+1]=2;else mp[i][j+1]=0;}}for (int i=1;i<=n;i++){scanf("%s",&ch);for (int j=0;j<m;j++)num[i][j+1]=ch[j]-'0';}if (cnt!=0){printf("-1");return 0;}lianbian();doit();return 0;
}

转载于:https://www.cnblogs.com/wutongtong3117/p/7673285.html

bzoj2668 [cqoi2012]交换棋子相关推荐

  1. 【BZOJ-2668】交换棋子 最小费用最大流

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 1055  Solved: 388 [Submit][Stat ...

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

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

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

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

  4. P3159 [CQOI2012]交换棋子(费用流)

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

  5. [CQOI2012]交换棋子【网络流】【费用流】

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

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

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

  7. 2668: [cqoi2012]交换棋子

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

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

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

  9. [bzoj2668]交换棋子

    基本思路是,要让所有黑点都相对应(所以首先判断黑点的个数). 如果没有交换限制,可以按以下方法建图:源点向所有初始黑点连(1,0)的边,最终黑点向汇点连(1,0)的边,相邻的两点连边(inf,1),最 ...

最新文章

  1. 利用BP神经网络教计算机识别语音特征信号(代码部分SS)
  2. python好学嘛-python语言好学吗
  3. 聚类之K-means均值聚类
  4. 【数学和算法】如何理解特征值为复数的情况
  5. MaxCompute中如何通过logview诊断慢作业
  6. pip install 报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xb5 in
  7. PocoClassGenerator:RDBMS所有表/视图生成Dapper POCO类代码
  8. linux磁盘及文件系统管理
  9. 高德地图三级行政区钻取
  10. 3D建模最常用的是那三款软件?
  11. 测试工程师-压力测试之jmeter脚本
  12. C++ 鼠标模拟程序
  13. 使用PHP从Access数据库中提取对象,第2部分
  14. css中实现三角形的几种方式
  15. POI XWPFParagraph.getRuns分段混乱问题解决
  16. 基于SpringBoot的在线课程管理系统
  17. JavaScript从入门到放弃到精通
  18. 数字图像隐写术之JPEG 隐写分析
  19. 高阶低通滤波算法_高/低算法
  20. 学是计算机审计的心得感受,计算机审计心得体会

热门文章

  1. 转载一份大佬的面试指南,命中率很高
  2. 数据结构(C语言版)之栈及递归
  3. pg_receivewal实践
  4. win10、win11高级共享设置修改后无法保存怎么办,无法发现网络设备、无法发现共享设备怎么办?win10、win11发现网络共享设备的方法
  5. 数据的入库操作 实验python_python操作MySQL数据库
  6. mactxt文件如何转换成html,最佳的用于Mac上的PDF文件转换到HTML文件的转换器
  7. 寓教于乐——玩转角色互换游戏
  8. 双控专业就业机器人_东北大学自动化双控考研专业就业方向
  9. HEVC解码器HM源码阅读(四)解析参数集
  10. bxl文件转换为AD可以用的原理图和PCB库文件