>Description
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。


>Input
第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)
第二行包含三个整数,表示目标位置x y z。(互不相同)

>Output
如果无解,输出一行NO。
如果可以到达,第一行输出YES,第二行输出最少步数。


>Sample Input
1 2 3
0 3 5

>Sample Output
YES
2

20% 输入整数的绝对值均不超过10
40% 输入整数的绝对值均不超过10000
100% 绝对值不超过10^9


>解题思路
题目大意:有一个线性的跳棋,问三个点的状态{a,b,c{a,b,c}a,b,c}能否到达{x,y,zx,y,zx,y,z},并且输出最小步数

设{a,b,c}为S1S_1S1​,{x,y,z}为S2S_2S2​
通过手动模拟可以发现,一组数据{a,b,c},a<b<ca<b<ca<b<c,可以达到三种状态:

  1. bbb向aaa的方向跳
  2. bbb向ccc的方向跳
  3. 离bbb近的点往bbb的方向跳,且当仅当b−a≠c−bb-a≠c-bb−a​=c−b(三个点均匀分布,这样子就跳不动)

我们可以发现1、2种跳的方法是扩大范围,第3种是缩小范围,所以我们可以把第3种设为根,把第1、2种设为两个子节点,因此b−a==c−bb-a==c-bb−a==c−b的状态为根节点
如果S1S_1S1​和S2S_2S2​的根节点相同,就说明S1S_1S1​可以到达S2S_2S2​

所以我们可以进行以下步骤:

  1. 往上跳,分别寻找S1S_1S1​,S2S_2S2​的根,判断这两个根节点是否相等
  2. 把S1S_1S1​和S2S_2S2​跳到同一高度
  3. 二分向上跳的步数,看两个状态跳跃以后分别达到的状态是否相同

这里有一个很重要的加速:

如果是这种距离很长的情况,可以直接用除数加速,当然要注意重合的情况
例如设d1=b−ad_1=b-ad1​=b−a,d2=c−bd_2=c-bd2​=c−b,可以直接用d1/d2d_1/d_2d1​/d2​加速


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;struct node
{int x, y, z;
} s1, s2, root[5];
int dep[5];bool check (node aa, node bb)
{if (aa.x != bb.x || aa.y != bb.y || aa.z != bb.z) return 0;return 1;
}
void ssort (node &aa)
{if (aa.x > aa.y) swap (aa.x, aa.y);if (aa.x > aa.z) swap (aa.x, aa.z);if (aa.y > aa.z) swap (aa.y, aa.z);
} //排序
void getroot (node aa, int ll)
{int l; while (aa.y - aa.x != aa.z - aa.y){int d1 = aa.y - aa.x, d2 = aa.z - aa.y;if (d1 > d2){l = d1 / d2;if (d1 % d2 == 0) l--;aa.y -= l * d2, aa.z -= l * d2;}else{l = d2 / d1;if (d2 % d1 == 0) l--;aa.x += l * d1, aa.y += l * d1;}dep[ll] += l; //累计状态在树中的深度ssort (aa);}root[ll] = (node) {aa.x, aa.y, aa.z};
} //找根
node jump (node aa, int k) //状态aa往上跳k步达到的状态
{int l;while (k){int d1 = aa.y - aa.x, d2 = aa.z - aa.y;if (d1 == d2) break; //跳到根了if (d1 > d2){l = d1 / d2;if (d1 % d2 == 0) l--;if (l > k) l = k; //防止越界aa.y -= l * d2, aa.z -= l * d2;}else{l = d2 / d1;if (d2 % d1 == 0) l--;if (l > k) l = k;aa.x += l * d1, aa.y += l * d1;}k -= l;ssort (aa);}return aa;
}int main()
{scanf ("%d%d%d", &s1.x, &s1.y, &s1.z);scanf ("%d%d%d", &s2.x, &s2.y, &s2.z);ssort (s1), ssort (s2);getroot (s1, 1);getroot (s2, 2); //找根if (!check (root[1], root[2])){printf ("NO");return 0;}int d = abs (dep[1] - dep[2]); //初始状态和最终状态相差的深度if (dep[1] > dep[2]) s1 = jump (s1, d);else if (dep[1] < dep[2]) s2 = jump (s2, d); //把深度深的跳到和深度浅的同一层int l = 0, r = min (dep[1], dep[2]), mid;int m = 0;while (l <= r){mid = (l + r) / 2;node p1 = jump (s1, mid);node p2 = jump (s2, mid);if (check (p1, p2)) m = mid, r = mid - 1;else l = mid + 1;}printf ("YES\n%d", d + 2 * m); //两点到LCA的路径长度return 0;
}

跳跳棋【LCA】【二分】相关推荐

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

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

  2. 跳跳棋[LCA+二分查找]-洛谷1852

    传送门 这真是一道神仙题 虽然我猜到了这是一道LCA的题 但是... 第一遍看题,我是怎么也没想到能和树形图扯上关系 并且用上LCA 但其实其实和上一道lightoj上的那道题很类似 只不过那时一道很 ...

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

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

  4. BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)【BZOJ修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2144 是 hydro 的 BZOJ ...

  5. BZOJ 2144 跳跳棋(LCA+欧几里德+二分答案)

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

  6. P1852 跳跳棋(建模LCA)

    P1852 跳跳棋(建模&LCA) 往外跳有个两个状态,往里跳只能有一个唯一父亲状态. 所以是一个二叉树. 将给定的起始和目标状态 向上找到根,判断是否相等.不相等无解. 否则类似求LCA的思 ...

  7. 跳跳棋(国家集训队,LCA,洛谷P1852,BZOJ[2144])

    文章目录 题目 思路 代码 题目 题目链接 描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有333颗棋子,分别在a,b,ca,b ...

  8. 不一样的LCA——luoguP1852跳跳棋

    在一条数轴上进行跳跳棋游戏.棋子只能摆在整点上.每个点不能摆超过一个棋子.用跳跳棋完成:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z. 跳动的规则:任 ...

  9. bzoj2144 [2011集训队出题] 跳跳棋 倍增 lca

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

最新文章

  1. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
  2. 常见排序算法时间复杂度
  3. python开发windows界面_python适合windows的桌面应用程序开发吗?
  4. 五、oracle 表的管理
  5. java sentence_Java Sentence類代碼示例
  6. 工作272:上传部分代码优化之两种上传视频的方式
  7. 现代软件工程 作业 结对编程 模板
  8. C# OpenFileDialog 使用
  9. 如何克隆服务器系统数据,Linode面板clone克隆功能实现服务器数据完整迁移
  10. 表白html苹果电脑,视频教你如何用苹果Mac 向女生表白!
  11. 极客大学架构师训练营 大数据架构 MapReduce Yarn Hive SQL 第24课 听课总结
  12. 个人网站,添加对方为好友,QQ临时对话设置方法
  13. ubuntu20.04不能切换输入法
  14. 个人网页制作(教你制作简单网页)
  15. win7如何创建宽带连接
  16. 计算机文化基础多选题答案,计算机基础多选题集(附答案)
  17. 【无标题】学习贪吃蛇代码
  18. 想让微信公众号文章上“朋友圈热文”?看看这个
  19. STM8L 简单定时器使用
  20. 「红米 2A 标准版」闪屏救砖、更正官方线刷救砖工具

热门文章

  1. 一个STAF的RC21的问题的解决和思考
  2. C#基于RealPlayX.ocx视频监控整合程序
  3. 阿里云办公安全产品专家高传贵:零信任,让全球办公安全更简单
  4. java还原三阶魔方_魔方小站四阶魔方教程2 一看就懂的魔方教程(魔方玩法视频教程+还原公式一步一步图解+3D动画)...
  5. 从“游击队”到“正规军”:虾神成长史
  6. android 监控id代码,茗伊插件 剑三技能监控代码
  7. Your IP address is spelled incorrectly问题排查
  8. 家庭風水的六大注意事項_家居风水自查
  9. Gym - 100889H Hitting Points 计算几何+三分+二分
  10. TiDB -- TiDB CDC POC 测试