【题目 描述】

跳跳棋是在一条数轴上进行的。 棋子只能摆在整点上。 每个点不能摆超过一
个棋子。 我们用跳跳棋来做一个简单的游戏: 棋盘上有 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】跳跳棋相关推荐

  1. [BZOJ2144]跳跳棋

    [BZOJ2144]跳跳棋 试题描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过 ...

  2. bzoj2144 跳跳棋

    Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...

  3. bzoj-2144 跳跳棋

    2144: 跳跳棋 题目链接 时间限制: 10 Sec 内存限制: 259 MB 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一 个简单的游戏: ...

  4. [bzoj2144]: 跳跳棋

    2144: 跳跳棋 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 689  Solved: 326 [Submit][Status][Discuss ...

  5. BZOJ2144跳跳棋——LCA+二分

    题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...

  6. bzoj2144: 跳跳棋(二分/倍增)

    思维好题! 可以发现如果中间的点要跳到两边有两种情况,两边的点要跳到中间最多只有一种情况. 我们用一个节点表示一种状态,那么两边跳到中间的状态就是当前点的父亲,中间的点跳到两边的状态就是这个点的两个儿 ...

  7. 洛谷1852 BZOJ2144 跳跳棋 思维题

    题目链接 题意: 坐标轴上告诉你三个互不相同的位置作为三个棋子的起点,再告诉你三个不同的位置作为三个棋子的终点,每次操作可以让一个棋子以另一个棋子为轴跳到对称位置,并且只能跳过一个棋子,问你是否能最终 ...

  8. BZOJ2144: 跳跳棋

    求三个人从a,b,c这三个位置跳到x,y,z最少多少步.跳:任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  从它跳的性质出发,向内跳只有一种操作,而向外跳有两种 ...

  9. [BZOJ2144]国家集训队 跳跳棋

    题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...

最新文章

  1. android——ImageLoader添加缓存
  2. ​浅谈Asp.net的sessionState
  3. 搜索引擎学习(二)Lucene创建索引
  4. O-R mapping工具
  5. 一个基于cocos2d-x 3.0和Box2d的demo小程序
  6. SAP CRM里business partner在订单处理中的determination流程
  7. Android开发之设置Edittext小数点后两位以及限制位数同时使用
  8. SQL Server:Like 通配符特殊用法:Escape
  9. Flask-第二课:路由
  10. MySQL空闲会话_使用Oracle PROFILE控制会话空闲时间
  11. 面试官竟让我用Redis实现一个消息队列!
  12. 【C语言】能不能更快?
  13. 【机器视觉】独家盘点:详解国内外34家物联网机器视觉技术企业
  14. tomcat普通用户启动不了
  15. 摄像机标定之四大坐标系之间转换关系详解
  16. 中国行政区域经纬度(免费下载)
  17. React Native多语言切换
  18. 利用datafaker批量生成测试数据
  19. websocket实现多房间聊天室
  20. 青蛙Pro绑定商户号(windows)

热门文章

  1. macOS Big Sur 11.6 (20G165) 虚拟机 IOS 镜像
  2. 2022全国水下机器人大赛国际线上赛来啦!“水下感知赛、通信赛”等你来战!
  3. 简易水下航行器舵控arduino,蓝牙通讯
  4. mui开发项目流程_mui项目开发环境搭建
  5. 10个优秀的Golang开源库类,武装生产力
  6. 台式计算机启动时 每次按f1,台式机电脑每次开机都要按F1,华硕主板
  7. 加密word去除密码教程
  8. 简单描述下我用MQTT协议连上阿里云的总结(EMW3080+AT指令)
  9. pmu2008终端服务器,PMU升级指导.doc
  10. 读书笔记之《好好说话》