zoukankan      html  css  js  c++  java
  • 跳跳棋——二分+建模LCA

    题目描述

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

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

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

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

    思路

    考虑一种类似于二叉树的结构,三个跳棋无法再跳的时候(即$|XY|=|YZ|$时),我把将它视为根,我们把初末状态视为$a,b$两个节点,那么其实就是找$a,b的LCA$,我们先找到$a,b$的根,如果根不同,没有解,否则我们先把$a,b$提到同一深度,记深度差为$x$,然后二分往上跳的高度,记为$l$,答案就是$x+l*2$

    code

    #include<bits/stdc++.h>
    #define I inline
    #define dist(x,y) (abs(x-y))
    using namespace std;
    const int inf=1e9+10;
    struct node
    {
        int x[5];
        int dep;
    }a,b;
    int depth;
    int ans;
    
    bool operator == (node a,node b)
    {
        sort(a.x+1,a.x+4);sort(b.x+1,b.x+4);
        for(int i=1;i<=3;i++)if(a.x[i]!=b.x[i])return 0;
        return 1;
    }
    
    I node calc(node a,int k)
    {
        int x=a.x[1],y=a.x[2],z=a.x[3];
        node res;
        for(int i=1;i<=3;i++)res.x[i]=a.x[i];
        int d1=dist(x,y),d2=dist(y,z);
        if(d1==d2)return res;
        if(d1<d2)
        {
            int t=min(k,(d2-1)/d1);
            x+=d1*t;y+=d1*t;
            k-=t;depth+=t;
        }
        else
        {
            int t=min(k,(d1-1)/d2);
            y-=d2*t;z-=d2*t;
            k-=t;depth+=t;
        }
        res.x[1]=x;res.x[2]=y;res.x[3]=z;
        if(k)return calc(res,k);
        return res;
    }
    
    int main()
    {
        cin>>a.x[1]>>a.x[2]>>a.x[3]>>b.x[1]>>b.x[2]>>b.x[3];
        sort(a.x+1,a.x+4);sort(b.x+1,b.x+4);
        node rt1=calc(a,inf);a.dep=depth;depth=0;
        node rt2=calc(b,inf);b.dep=depth;depth=0;
        if(!(rt1==rt2)){cout<<"NO";return 0;}
        if(a.dep<b.dep)swap(a,b);
        ans=a.dep-b.dep;
        a=calc(a,ans);
        int l=0,r=b.dep;
        while(l<r-1)
        {
            int mid=l+r>>1;
            if(calc(a,mid)==calc(b,mid))r=mid;
            else l=mid;
        }
        while(!(calc(a,l)==calc(b,l)))l++;
        puts("YES");
        cout<<ans+l*2;
        
    }
  • 相关阅读:
    Delphi关于记录文件的操作转
    数字电视分辨率
    delphi FileSetAttr 设置文件的属性转
    vc delphi 回调函数具体说明和实例与分析 转
    TFileStream(文件流) 读写转
    HDMI接口
    UDP和TCP协议包大小的计算转
    字符编解码的故事(ASCII,ANSI,Unicode,Utf8) 转
    [bzoj3894]文理分科
    [bzoj5338]xor
  • 原文地址:https://www.cnblogs.com/THRANDUil/p/11792715.html
Copyright © 2011-2022 走看看