跳跳棋【LCA】【二分】
>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,可以达到三种状态:
- bbb向aaa的方向跳
- bbb向ccc的方向跳
- 离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
所以我们可以进行以下步骤:
- 往上跳,分别寻找S1S_1S1,S2S_2S2的根,判断这两个根节点是否相等
- 把S1S_1S1和S2S_2S2跳到同一高度
- 二分向上跳的步数,看两个状态跳跃以后分别达到的状态是否相同
这里有一个很重要的加速:
如果是这种距离很长的情况,可以直接用除数加速,当然要注意重合的情况
例如设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】【二分】相关推荐
- BZOJ2144跳跳棋——LCA+二分
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- 跳跳棋[LCA+二分查找]-洛谷1852
传送门 这真是一道神仙题 虽然我猜到了这是一道LCA的题 但是... 第一遍看题,我是怎么也没想到能和树形图扯上关系 并且用上LCA 但其实其实和上一道lightoj上的那道题很类似 只不过那时一道很 ...
- bzoj2144: 跳跳棋(二分/倍增)
思维好题! 可以发现如果中间的点要跳到两边有两种情况,两边的点要跳到中间最多只有一种情况. 我们用一个节点表示一种状态,那么两边跳到中间的状态就是当前点的父亲,中间的点跳到两边的状态就是这个点的两个儿 ...
- BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)【BZOJ修复工程】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2144 是 hydro 的 BZOJ ...
- BZOJ 2144 跳跳棋(LCA+欧几里德+二分答案)
跳跳棋 问题描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位 ...
- P1852 跳跳棋(建模LCA)
P1852 跳跳棋(建模&LCA) 往外跳有个两个状态,往里跳只能有一个唯一父亲状态. 所以是一个二叉树. 将给定的起始和目标状态 向上找到根,判断是否相等.不相等无解. 否则类似求LCA的思 ...
- 跳跳棋(国家集训队,LCA,洛谷P1852,BZOJ[2144])
文章目录 题目 思路 代码 题目 题目链接 描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有333颗棋子,分别在a,b,ca,b ...
- 不一样的LCA——luoguP1852跳跳棋
在一条数轴上进行跳跳棋游戏.棋子只能摆在整点上.每个点不能摆超过一个棋子.用跳跳棋完成:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z. 跳动的规则:任 ...
- bzoj2144 [2011集训队出题] 跳跳棋 倍增 lca
Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把 ...
最新文章
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
- 常见排序算法时间复杂度
- python开发windows界面_python适合windows的桌面应用程序开发吗?
- 五、oracle 表的管理
- java sentence_Java Sentence類代碼示例
- 工作272:上传部分代码优化之两种上传视频的方式
- 现代软件工程 作业 结对编程 模板
- C# OpenFileDialog 使用
- 如何克隆服务器系统数据,Linode面板clone克隆功能实现服务器数据完整迁移
- 表白html苹果电脑,视频教你如何用苹果Mac 向女生表白!
- 极客大学架构师训练营 大数据架构 MapReduce Yarn Hive SQL 第24课 听课总结
- 个人网站,添加对方为好友,QQ临时对话设置方法
- ubuntu20.04不能切换输入法
- 个人网页制作(教你制作简单网页)
- win7如何创建宽带连接
- 计算机文化基础多选题答案,计算机基础多选题集(附答案)
- 【无标题】学习贪吃蛇代码
- 想让微信公众号文章上“朋友圈热文”?看看这个
- STM8L 简单定时器使用
- 「红米 2A 标准版」闪屏救砖、更正官方线刷救砖工具
热门文章
- 一个STAF的RC21的问题的解决和思考
- C#基于RealPlayX.ocx视频监控整合程序
- 阿里云办公安全产品专家高传贵:零信任,让全球办公安全更简单
- java还原三阶魔方_魔方小站四阶魔方教程2 一看就懂的魔方教程(魔方玩法视频教程+还原公式一步一步图解+3D动画)...
- 从“游击队”到“正规军”:虾神成长史
- android 监控id代码,茗伊插件 剑三技能监控代码
- Your IP address is spelled incorrectly问题排查
- 家庭風水的六大注意事項_家居风水自查
- Gym - 100889H Hitting Points 计算几何+三分+二分
- TiDB -- TiDB CDC POC 测试