[国家集训队]跳跳棋

给这道题跪了......

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

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

对于一种位置状态 a  b  c

因为一次只允许跳过一个棋子可知如果中间的棋子如果不是三个棋的中点,则必定只有一种跳法使左边或右边的棋跳到中间,中间的棋任何时候都可以跳到两边。

由此可得出,将两边的棋子不断往中间跳得到一初始位置,则给定的a b c位置的所有能到达的位置都能由该初始位置得出。

首先判断目标状态和给定状态的初始状态是否相同,否则输出NO

若相同,二分lca向不断向中间跳,即可得出答案。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define il inline
using namespace std;
int a,b,c,x,y,z;
struct node
{
    int a,b,c;
    il void sor() { if(x > y) swap(x,y); if(x > z) swap(x,z); if(y > z) swap(y,z); }
}d1,d2,d3,d4,d5,d6;
il int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')op = -1;
        ch=getchar();}
    while(ch >= '0' && ch <= '9'){
        ans = (ans * 10) + ch - '0';
        ch = getchar();}
    return ans * op;
}
il int get_root(node& x){
    int step=0;
    x.sor();
    while(x.a + x.c != 2 * x.b)
    {
        int m1 = x.b-x.a,m2 = x.c-x.b;
        if(m1 < m2)
        {
            int temp = m2 / m1;
            if(m2 % m1 == 0) temp --;
            x.a += temp * m1;
            x.b += temp * m1;
            x.sor(); step += temp;
        }
        else
        {
            int temp = m1 / m2;
            if(m1 % m2 == 0) temp--;
            x.c -= temp * m2;
            x.b -= temp * m2;
            x.sor(); step += temp;
        }
    }
    return step;
}
node get_poi(node x,int step)
{
    x.sor();
    while(step)
    {
        int m1 = x.b - x.a,m2 = x.c - x.b;
        if(m1 < m2)
        {
            int temp = m2 / m1;
            if(m2 % m1 == 0) temp--;
            temp = min(temp,step);
            x.a += temp * m1;
            x.b += temp * m1;
            x.sor(); step-=temp;
        }
        else
        {
            int temp = m1 / m2;
            if(m1 % m2 == 0) temp--;
            temp = min(temp,step);
            x.c -= temp * m2;
            x.b -= temp * m2;
            x.sor(); step -= temp;
        }
    }
    return x;
}
il bool same(node x,node y)
{ return x.a == y.a && x.b == y.b && x.c == y.c; }
int main(){
    d1.a=read();d1.b=read();d1.c=read();
    d2.a=read();d2.b=read();d2.c=read();
    d1.sor();d2.sor();
    d5 = d1;d6 = d2;
    int step1 = get_root(d5),step2 = get_root(d6);
    if(same(d5,d6)) printf("YES\n");
    else{ printf("NO");    return 0; }
    int k=abs(step1-step2),ans=0;
    if(step1>=step2) d1 = get_poi(d1,k);
    else d2 = get_poi(d2,k);
    int le = 0,ri = min(step1,step2);
    while(le <= ri)
    {
        int mid = le + ri >> 1;
        d3 = get_poi(d1,mid);
        d4 = get_poi(d2,mid);
        if(same(d3,d4)) ans = mid,ri = mid - 1;
        else le = mid + 1;
    }
    printf("%d",ans * 2 + k);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/charlesss/p/10610582.html