【BZOJ2144】跳跳棋
【题目 描述】
跳跳棋是在一条数轴上进行的。 棋子只能摆在整点上。 每个点不能摆超过一
个棋子。 我们用跳跳棋来做一个简单的游戏: 棋盘上有 3 颗棋子, 分别在 a, b,
c 这三个位置。 我们要通过最少的跳动把他们的位置移动成 x, y, z。 (棋子是
没有区别的) 跳动的规则很简单, 任意选一颗棋子, 对一颗中轴棋子跳动。 跳动
后两颗棋子距离不变。 一次只允许跳过 1 颗棋子。
写一个程序, 首先判断是否可以完成任务。 如果可以, 输出最少需要的跳动次数。
【输入格式】
第一行包含三个整数, 表示当前棋子的位置 a b c。 (互不相同)
第二行包含三个整数, 表示目 标位置 x y z。 (互不相同)
【输出格式】
如果无解, 输出一行 NO。 如果可以到达, 第一行输出 YES, 第二行输出最少步数。
【样例输入】
1 2 3
0 3 5
【样例输出】
YES
2提示
100% 绝对值不超过 10^9
刚开始看到这道题真的没什么想法,真是道神秘的好题啊(~)
后来在草稿上自己画了几种状态,发现(!)每一种状态,只能发展出三种状态, 1.中间向左跳 2.中间向右跳 3.两边的某一个向中间跳(当然根节点状态不行)
如果把一种状态疯狂地向中间折叠,会跳到一个平衡的状态,两边再也无法向中间跳了,这个状态其实就是根,而从这个状态向外发展出去,每次都只会发展出两种,所以发现这些状态构成了一棵二叉树,只要任意两种状态都能变成相同的根节点状态,那么它们一定可以相互转化(!)
所以问题就转化成求树上两个不同节点的距离了。
我先让两个节点跳到一个相同的深度,再二分距离,让这两个节点同时向上跳,最后得出答案。
哦对了,向上跳(向内折叠)时发现可以用除法来加速,一下子可以折好大一段,没有必要每一次都是加法模拟(那样会超时的)
(不知为什么我的代码很长)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 8 #define For(i,a,b) for(register int i=a;i<=b;++i) 9 #define Re register 10 using namespace std; 11 struct Bal{ 12 int x,y,z; 13 }b1,b2,rb1,rb2,bx1,bx2; 14 int tp1,tp2; 15 inline void read(int &v){ 16 v=0; bool fg=0; 17 char c=getchar(); if(c=='-')fg=1; 18 while(c<'0'||c>'9'){c=getchar(); if(c=='-')fg=1;} 19 while(c>='0'&&c<='9'){v=v*10+c-'0',c=getchar(); if(c=='-')fg=1;} 20 if(fg)v=-v; 21 } 22 23 void getNT(Bal &b){ //使x,y,z有序 24 if(b.x>b.y)swap(b.x,b.y); 25 if(b.x>b.z)swap(b.x,b.z); 26 if(b.y>b.z)swap(b.y,b.z); 27 } 28 29 int ComeBack(Bal &b){ //跳到根节点 30 int stp=0; 31 getNT(b); 32 while(b.x+b.z!=b.y*2){ 33 int d1=b.y-b.x; 34 int d2=b.z-b.y; 35 if(d1<d2){ 36 int tp=d2/d1; 37 if(d2%d1==0)tp--; 38 b.x+=tp*d1; 39 b.y+=tp*d1; 40 if(b.x>b.y)swap(b.x,b.y); 41 stp+=tp; 42 }else{ 43 int tp=d1/d2; 44 if(d1%d2==0)tp--; 45 b.y-=tp*d2; 46 b.z-=tp*d2; 47 if(b.z<b.y)swap(b.z,b.y); 48 stp+=tp; 49 } 50 } 51 return stp; 52 } 53 54 bool QL(Bal a,Bal b){ 55 if(a.x==b.x&&a.y==b.y&&a.z==b.z)return 1; 56 return 0; 57 } 58 59 Bal CheckandGo(Bal bl,int Lim){ //二分出可以向上跳的距离然后向上跳 60 Bal b=bl; 61 int Lm=Lim; 62 getNT(b); 63 while(Lm){ 64 int d1=b.y-b.x; 65 int d2=b.z-b.y; 66 if(d1<d2){ 67 int tp=d2/d1; 68 if(d2%d1==0)tp--; 69 if(tp>Lm)tp=Lm; 70 b.x+=tp*d1; 71 b.y+=tp*d1; 72 if(b.x>b.y)swap(b.x,b.y); 73 Lm-=tp; 74 }else{ 75 int tp=d1/d2; 76 if(d1%d2==0)tp--; 77 if(tp>Lm)tp=Lm; 78 b.y-=tp*d2; 79 b.z-=tp*d2; 80 if(b.z<b.y)swap(b.z,b.y); 81 Lm-=tp; 82 } 83 if(Lm==0)break; 84 } 85 return b; 86 } 87 88 int main(){ 89 // freopen("hop.in","r",stdin); 90 // freopen("hop.out","w",stdout); 91 read(b1.x); read(b1.y); read(b1.z); 92 read(b2.x); read(b2.y); read(b2.z); 93 94 getNT(b1); getNT(b2); 95 bx1=b1; bx2=b2; 96 tp1=ComeBack(bx1); tp2=ComeBack(bx2); 97 98 99 if(!QL(bx1,bx2)){ 100 printf("NO"); 101 }else{ 102 int bs=abs(tp1-tp2); 103 int l=0,r=min(tp1,tp2),ff; 104 105 if(tp1<tp2){//跳到同一深度 106 b2=CheckandGo(b2,bs); 107 }else{ 108 b1=CheckandGo(b1,bs); 109 } 110 111 while(l<=r){ //二分 112 int m=(l+r)>>1; 113 bx1=CheckandGo(b1,m); 114 bx2=CheckandGo(b2,m); 115 if(QL(bx1,bx2))ff=m,r=m-1; 116 else l=m+1; 117 } 118 cout<<"YES"<<endl; 119 cout<<bs+ff*2<<endl; 120 } 121 return 0; 122 }
转载于:https://www.cnblogs.com/HLAUV/p/9883140.html
【BZOJ2144】跳跳棋相关推荐
- [BZOJ2144]跳跳棋
[BZOJ2144]跳跳棋 试题描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过 ...
- bzoj2144 跳跳棋
Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...
- bzoj-2144 跳跳棋
2144: 跳跳棋 题目链接 时间限制: 10 Sec 内存限制: 259 MB 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一 个简单的游戏: ...
- [bzoj2144]: 跳跳棋
2144: 跳跳棋 Time Limit: 10 Sec Memory Limit: 259 MB Submit: 689 Solved: 326 [Submit][Status][Discuss ...
- BZOJ2144跳跳棋——LCA+二分
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- bzoj2144: 跳跳棋(二分/倍增)
思维好题! 可以发现如果中间的点要跳到两边有两种情况,两边的点要跳到中间最多只有一种情况. 我们用一个节点表示一种状态,那么两边跳到中间的状态就是当前点的父亲,中间的点跳到两边的状态就是这个点的两个儿 ...
- 洛谷1852 BZOJ2144 跳跳棋 思维题
题目链接 题意: 坐标轴上告诉你三个互不相同的位置作为三个棋子的起点,再告诉你三个不同的位置作为三个棋子的终点,每次操作可以让一个棋子以另一个棋子为轴跳到对称位置,并且只能跳过一个棋子,问你是否能最终 ...
- BZOJ2144: 跳跳棋
求三个人从a,b,c这三个位置跳到x,y,z最少多少步.跳:任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子. 从它跳的性质出发,向内跳只有一种操作,而向外跳有两种 ...
- [BZOJ2144]国家集训队 跳跳棋
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
最新文章
- android——ImageLoader添加缓存
- ​浅谈Asp.net的sessionState
- 搜索引擎学习(二)Lucene创建索引
- O-R mapping工具
- 一个基于cocos2d-x 3.0和Box2d的demo小程序
- SAP CRM里business partner在订单处理中的determination流程
- Android开发之设置Edittext小数点后两位以及限制位数同时使用
- SQL Server:Like 通配符特殊用法:Escape
- Flask-第二课:路由
- MySQL空闲会话_使用Oracle PROFILE控制会话空闲时间
- 面试官竟让我用Redis实现一个消息队列!
- 【C语言】能不能更快?
- 【机器视觉】独家盘点:详解国内外34家物联网机器视觉技术企业
- tomcat普通用户启动不了
- 摄像机标定之四大坐标系之间转换关系详解
- 中国行政区域经纬度(免费下载)
- React Native多语言切换
- 利用datafaker批量生成测试数据
- websocket实现多房间聊天室
- 青蛙Pro绑定商户号(windows)
热门文章
- macOS Big Sur 11.6 (20G165) 虚拟机 IOS 镜像
- 2022全国水下机器人大赛国际线上赛来啦!“水下感知赛、通信赛”等你来战!
- 简易水下航行器舵控arduino,蓝牙通讯
- mui开发项目流程_mui项目开发环境搭建
- 10个优秀的Golang开源库类,武装生产力
- 台式计算机启动时 每次按f1,台式机电脑每次开机都要按F1,华硕主板
- 加密word去除密码教程
- 简单描述下我用MQTT协议连上阿里云的总结(EMW3080+AT指令)
- pmu2008终端服务器,PMU升级指导.doc
- 读书笔记之《好好说话》