bzoj2668 [cqoi2012]交换棋子
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]交换棋子相关推荐
- 【BZOJ-2668】交换棋子 最小费用最大流
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 1055 Solved: 388 [Submit][Stat ...
- BZOJ 2668: [cqoi2012]交换棋子
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 1112 Solved: 409 [Submit][Stat ...
- BZOJ2668:[CQOI2012]交换棋子——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...
- P3159 [CQOI2012]交换棋子(费用流)
题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第 ...
- [CQOI2012]交换棋子【网络流】【费用流】
题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第一行 ...
- 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子
有一个\(n\)行\(m\)列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第\(i\)行第\(j\)列的格子只能参与\(m[i][j]\)次交换 ...
- 2668: [cqoi2012]交换棋子
Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...
- 洛谷P3159 [CQOI2012]交换棋子
巧妙的拆点方式,首先把1看成黑点,0看成空的,几次交换就可以看成一条路径 1)从容量上看,这条路径为1-2-2-2-2-2----2-1 2)从费用上看,这条路径每条边费用都是1 于是用一种巧妙的拆点 ...
- [bzoj2668]交换棋子
基本思路是,要让所有黑点都相对应(所以首先判断黑点的个数). 如果没有交换限制,可以按以下方法建图:源点向所有初始黑点连(1,0)的边,最终黑点向汇点连(1,0)的边,相邻的两点连边(inf,1),最 ...
最新文章
- 利用BP神经网络教计算机识别语音特征信号(代码部分SS)
- python好学嘛-python语言好学吗
- 聚类之K-means均值聚类
- 【数学和算法】如何理解特征值为复数的情况
- MaxCompute中如何通过logview诊断慢作业
- pip install 报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xb5 in
- PocoClassGenerator:RDBMS所有表/视图生成Dapper POCO类代码
- linux磁盘及文件系统管理
- 高德地图三级行政区钻取
- 3D建模最常用的是那三款软件?
- 测试工程师-压力测试之jmeter脚本
- C++ 鼠标模拟程序
- 使用PHP从Access数据库中提取对象,第2部分
- css中实现三角形的几种方式
- POI XWPFParagraph.getRuns分段混乱问题解决
- 基于SpringBoot的在线课程管理系统
- JavaScript从入门到放弃到精通
- 数字图像隐写术之JPEG 隐写分析
- 高阶低通滤波算法_高/低算法
- 学是计算机审计的心得感受,计算机审计心得体会
热门文章
- 转载一份大佬的面试指南,命中率很高
- 数据结构(C语言版)之栈及递归
- pg_receivewal实践
- win10、win11高级共享设置修改后无法保存怎么办,无法发现网络设备、无法发现共享设备怎么办?win10、win11发现网络共享设备的方法
- 数据的入库操作 实验python_python操作MySQL数据库
- mactxt文件如何转换成html,最佳的用于Mac上的PDF文件转换到HTML文件的转换器
- 寓教于乐——玩转角色互换游戏
- 双控专业就业机器人_东北大学自动化双控考研专业就业方向
- HEVC解码器HM源码阅读(四)解析参数集
- bxl文件转换为AD可以用的原理图和PCB库文件