P1852跳跳棋 题解
好妙啊!这道题让我大开眼界!
写一篇题解加深一下印象。
思路
我重点对把原问题建模成一个树上问题的部分进行补充。
最开始读题的时候没有看到最多只跳过一个棋子,没想到这竟然是突破口。
我们假设一个状态 ,不妨设 。
考虑它能怎么变化?这里为了方便描述,在引入两个变量 表示 和 与 之间的距离。
它会有以下几种变换方式:
-
向左跳,,
-
向右跳,,
-
向右(中间)跳, ,
-
向左(中间)跳, ,
可以发现由于最多只跳过一个棋子,, 操作必然矛盾。
换句话说,假如只进行 , 操作操作将是唯一的(会操作小的那边)!(\震惊)
这里有一个小发现: 操作和 操作是互逆的:
比如 进行 操作 变成 ; 进行 操作 又变回 。
思考继续深入。每次 的范围都会减少 。
范围会在某个状态重新变大吗或无法变化吗?
答案是后者。我们刚才忘记讨论 的情况了!假如 那就无法操作了。
我们假设这样的状态为 。
从 到 要进行的操作是不确定的 (, 其中一种)。
而从 到 要进行的操作是确定的(, 其中一种)。
并且 和 操作是互逆的。
二叉树不就是这样的吗?走到儿子和回到父亲是互逆的。儿子有多个,不确定;父亲只有一个,确定。
所以从原始状态到目标状态的过程对应的就是树上两点的距离。
设原始状态,目标状态分别为 , 。
解决方法就是先找到 LCA
,再计算出 , 到 LCA
的距离(用 操作唯一解决)
剩下部分可以参考别的题解,主要的就是我这里的 jump
函数。
#include<bits/stdc++.h> using namespace std; struct node{ int x, y, z; // void print() { // cout << x << " " << y << " " << z << "\n"; // } bool operator == (node T) { return (x == T.x && y == T.y && z == T.z); } }A, B; pair<node, int> get(int x, int y, int z) { int res = 0; while(1) { int d1 = y - x, d2 = z - y; if(d1 == d2) break; if(d1 < d2) { int s = (d2 - 1) / d1; y = z - d2 + s * d1; x = y - d1; res += s; } else { int s = (d1 - 1) / d2; y = x + d1 - s * d2; z = y + d2; res += s; } } return {(node){x, y, z}, res}; }// 跳到根的步数 node jump(int x, int y, int z, int step) { while(step) { int d1 = y - x, d2 = z - y; if(d1 == d2) break; if(d1 < d2) { int s = min(step, (d2 - 1) / d1); y = z - d2 + s * d1; x = y - d1; step -= s; } else { int s = min(step, (d1 - 1) / d2); y = x + d1 - s * d2; z = y + d2; step -= s; } } return (node){x, y, z}; }// 跳 step 步到的点 void init(node &P) { int a, b, c; cin >> a >> b >> c; P.x = min({a, b, c}); P.z = max({a, b, c}); P.y = a + b + c - P.x - P.z; } int main() { init(A), init(B); auto tmp1 = get(A.x, A.y, A.z); auto tmp2 = get(B.x, B.y, B.z); if(!(tmp1.first == tmp2.first)) { cout << "NO"; return 0; } cout << "YES\n"; int tot1 = tmp1.second, tot2 = tmp2.second; if(tot1 < tot2) swap(A, B), swap(tot1, tot2); A = jump(A.x, A.y, A.z, tot1 - tot2); int l = 0, r = 1e9, ans = 0; while(l <= r) { int mid = (l + r) / 2; if(jump(A.x, A.y, A.z, mid) == jump(B.x, B.y, B.z, mid)) { ans = mid, r = mid - 1; } else l = mid + 1; } cout << ans * 2 + tot1 - tot2; return 0; }
本文作者:merlinkkk
本文链接:https://www.cnblogs.com/merlinkkk/p/18727276
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步