• P1852 [国家集训队]跳跳棋


    P1852 [国家集训队]跳跳棋

    题目描述

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

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

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

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

    输入输出格式

    输入格式:

    第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)

    第二行包含三个整数,表示目标位置x y z。(互不相同)

    输出格式:

    如果无解,输出一行NO。

    如果可以到达,第一行输出YES,第二行输出最少步数。

    输入输出样例

    输入样例#1: 复制
    1 2 3
    0 3 5
    输出样例#1: 复制
    YES
    2

    说明

    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);
    }
    View Code
  • 相关阅读:
    捕获Java线程池执行任务抛出的异常
    Java Singleton 单例模式
    深度解析Java内存的原型及工作原理
    使用Spring管理数据源连接池
    Java中用内存映射处理大文件
    基于Java阻塞队列的搜索实例
    Java学习之将图片文件保存到数据库
    Java使用反射调用方法
    Java程序员易犯的10个SQL错误
    Hibernate中的数据库增改删查操作
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9904803.html
Copyright © 2020-2023  润新知