• LCA——luoguP1852跳跳棋


    Problem:

    洛谷端题目链接

    loj端题目链接

    题目大意:

    在一条数轴上进行跳跳棋游戏。棋子只能摆在整点上。每个点不能摆超过一个棋子。用跳跳棋完成:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。

    跳动的规则:任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。如果可以完成输出YES以及所需步数,如果不行输出NO即可。

    对,只允许跳过一颗棋子(因为这个想了好久自闭了)


    Solution:

    看完题目之后第一反应是不是:woc这什么,跟LCA有什么关系??这哪来的树??

    那就对了(%dalao)

    分类讨论,发现对于每一种合法的状态(也就是没有棋子重合)只有三种情况能走

    1.中点(y)向左边跳

    2.中点(y)向右边跳

    3.左边(或者右边)往中间跳 =>可以证明由于只能跳过一颗棋子,在d1!=d2时只能走一个

    这好像有点像二叉树?(将1.2看做子节点,3看做父亲节点)

    对于1.2情况,我们可以发现(以下以1为例):

    可以知道,d1>d2时左边的棋子不能跳了,我们最多走d2/d1步,此时d2小于d1了换个方向走,当d2%d1等于0时走d2/d1-1步就到根了。

    所以根据这个,我们可以求出开始状态与结束状态的祖先,判断他们的祖先是否相等 =>因为祖先相同就可以通过相反操作得到

    这个操作模拟一下就好了,我们可以用除来加快跳((一个个跳会超时的)

    模拟部分:

     1                 int d1=y-x;
     2         int d2=z-y;
     3         if(d1<d2)
     4         {
     5             int step=d2/d1;
     6             if(d2%d1==0)    step--;
     7             if(step>dis)    step=dis;
     8             x+=step*d1;
     9             y+=step*d1;
    10             if(x>y)    swap(x,y);
    11             dis-=step;
    12         }
    13         else
    14         {
    15             int step=d1/d2;
    16             if(d1%d2==0)    step--;
    17             if(step>dis)    step=dis;
    18             z-=d2*step;
    19             y-=d2*step;
    20             if(z<y)    swap(z,y);
    21             dis-=step;
    22         }        
    View Code

    找到了公共祖先之后就可以二分查找(查找往上跳的步数) 

    l是0,r是min(结果与公共祖先的距离,起点与公共祖先的距离)

    1                 int l=0,r=min(dep1,dep2),step=0;
    2             while(l<=r)
    3         {
    4             int mid=l+r>>1;
    5             b1=go(st,mid);
    6             b2=go(ed,mid);
    7             if(pd(b1,b2))    step=mid,r=mid-1;
    8             else    l=mid+1;
    9         }      
    View Code

    以上是我认为的核心内容(看不懂就感性理解一下)


    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct node{
        int x,y,z;
    }st,ed,b1,b2;
    int dep1,dep2;
    inline int read(){
        char ch;
        int sign=1;
        while((ch=getchar())<'0'||ch>'9')
            if(ch=='-')    sign=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+ch-'0';
        return res*sign;
    }
    inline void sort(node &x){
        if(x.x>x.y)    swap(x.x,x.y);
        if(x.x>x.z)    swap(x.x,x.z);
        if(x.y>x.z)    swap(x.y,x.z);
    }
    inline int findfather(node &b){
        int res=0;
        sort(b);
        while(b.x+b.z!=b.y*2){
            int d1=b.y-b.x;
            int d2=b.z-b.y;
            if(d1<d2){
                int step=d2/d1;
                if(d2%d1==0)    step--;
                b.x+=step*d1;
                b.y+=step*d1;
                if(b.x>b.y)    swap(b.x,b.y);
                res+=step;
                }else{
                int step=d1/d2;
                if(d1%d2==0)    step--;
                b.z-=step*d2;
                b.y-=step*d2;
                if(b.y>b.z)    swap(b.y,b.z);
                res+=step;
            }
        }
        return res;
    }
    inline bool pd(node x,node y){
        if(x.x==y.x&&x.y==y.y&&x.z==y.z)    return true;
        return false;
    }
    inline int abs(int x){
        return x>=0?x:-x;
    }
    inline node go(node b,int dis){
        sort(b);
        while(dis){
            int d1=b.y-b.x;
            int d2=b.z-b.y;
            if(d1<d2){
                int step=d2/d1;
                  if(d2%d1==0)    step--;
                if(step>dis)    step=dis;
                b.x+=step*d1;
                b.y+=step*d1;
                if(b.x>b.y)    swap(b.x,b.y);
                dis-=step;
            }else{
                int step=d1/d2;
                if(d1%d2==0)    step--;
                if(step>dis)    step=dis;
                b.z-=d2*step;
                b.y-=d2*step;
                if(b.z<b.y)    swap(b.z,b.y);
                dis-=step;
            }
        }
        return b;
    }
    int main(){
        st.x=read();st.y=read();st.z=read();
        ed.x=read();ed.y=read();ed.z=read();
        sort(st);sort(ed);
        b1=st;b2=ed;
        dep1=findfather(b1);
        dep2=findfather(b2);
        if(!pd(b1,b2)){
            printf("NO\n");
            return 0;
        }else{
            int c=abs(dep1-dep2);
            if(dep1<dep2)
                ed=go(ed,c);
            else if(dep1>dep2)
                st=go(st,c);
            int l=0,r=min(dep1,dep2),step=0;
            while(l<=r){
                int mid=l+r>>1;
                b1=go(st,mid);
                b2=go(ed,mid);
                if(pd(b1,b2))    step=mid,r=mid-1;
                else    l=mid+1;
            }
            printf("YES\n");
            printf("%d",step*2+c);
        }
        return 0;
    }
    complete code
  • 相关阅读:
    Visual Studio 2005 ReportViewer 自适应报表大小显示
    【Vegas原创】SharePoint 503 Service Unavailable Error解决方法
    【Vegas改编】用C#实现浏览文件夹功能
    【Vegas2010】最后的g.cn
    【Vegas原创】SQL Server游标的经典使用
    命名规范(变量、控件)
    【Vegas原创】outlook发送时,报550 5.7.1 client does not have permissions to send as this sender解决方法
    【Vegas原创】Winform中使用MaskedTextBox制作IP地址输入框
    【Vegas原创】Apache2.2 + PHP5.3.2 + Oracle 10g配置
    IT职涯路
  • 原文地址:https://www.cnblogs.com/FridayZ/p/11847060.html
Copyright © 2020-2023  润新知