P1852 [国家集训队]跳跳棋
Posted edsheeran
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1852 [国家集训队]跳跳棋相关的知识,希望对你有一定的参考价值。
P1852 [国家集训队]跳跳棋
题目描述
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。
我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
输入输出格式
输入格式:
第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)
第二行包含三个整数,表示目标位置x y z。(互不相同)
输出格式:
如果无解,输出一行NO。
如果可以到达,第一行输出YES,第二行输出最少步数。
输入输出样例
说明
20% 输入整数的绝对值均不超过10
40% 输入整数的绝对值均不超过10000
100% 绝对值不超过10^9
题解:一道好题,考思维和代码
抽象的树型结构,向中间跳就是指向父亲节点,向两边跳就是指向儿子结点,判断两个状态是否合法,先判断是否在同一颗树中,倍增跳到同一深度后,在二分跳的步数直到相遇。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int M = 1e5 + 5; #define For(i, b, c) for(int i = b; i <= c; i++) #define ll long long int t[4], s[4], ori[4], tgr[4]; ll go(int a, int b, int c){ if(c - b == b - a){ t[1] = a, t[2] = b, t[3] = c; return 0; } if(c - b > b - a){ int dx = b - a; int cx = (c - b)/dx, res = (c - b)%dx; if(!res) cx--, res += dx; return cx + go(c - dx - res, c - res, c); } else { int dx = c - b; int cx = (b - a)/dx, res = (b - a)%dx; if(!res) cx--, res += dx; return cx + go(a, a + res, a + res + dx); } } void up(int a, int b, int c, ll lim){ if(!lim || b - a == c - b){ t[1] = a, t[2] = b, t[3] = c; return ; } if(c - b > b - a){ int dx = b - a; int cx = (c - b)/dx, res = (c - b)%dx; if(!res) cx--, res += dx; if(cx > lim){ up(a + dx*lim, a + dx*(lim+1), c, 0); } else up(c - dx - res, c - res, c, lim - cx); } else { int dx = c - b; int cx = (b - a)/dx, res = (b - a)%dx; if(!res) cx--, res += dx; if(cx > lim){ up(a, c - dx*(lim+1), c - dx*lim, 0); } else up(a, a + res, a + res + dx, lim - cx); } } bool check(ll k){ up(ori[1], ori[2], ori[3], k); For(i, 1, 3) s[i] = t[i]; up(tgr[1], tgr[2], tgr[3], k); For(i, 1, 3) if(s[i] != t[i])return 0; return 1; } int main(){ scanf("%d%d%d%d%d%d",&ori[1], &ori[2], &ori[3], &tgr[1], &tgr[2], &tgr[3]); sort(ori+1, ori+4); sort(tgr+1, tgr+4); ll stp1 = go(ori[1], ori[2], ori[3]); For(i, 1, 3) s[i] = t[i]; ll stp2 = go(tgr[1], tgr[2], tgr[3]); For(i, 1, 3) if(t[i] != s[i]){ puts("NO");return 0; } ll tmp = 0; if(stp1 > stp2){ tmp = stp1 - stp2; up(ori[1], ori[2], ori[3], tmp); For(i, 1, 3)ori[i] = t[i]; } else if(stp1 < stp2){ tmp = stp2 - stp1; up(tgr[1], tgr[2], tgr[3], tmp); For(i, 1, 3)tgr[i] = t[i]; } ll lf = 0, rg = min(stp1, stp2), ans = -1; while(lf <= rg){ ll mid = (lf + rg) >> 1; if(check(mid))rg = mid - 1, ans = mid; else lf = mid + 1; } printf("YES %lld ",tmp + ans*2); }
以上是关于P1852 [国家集训队]跳跳棋的主要内容,如果未能解决你的问题,请参考以下文章