• 【BZOJ2144】跳跳棋


    题目 描述】

    跳跳棋是在一条数轴上进行的。 棋子只能摆在整点上。 每个点不能摆超过一
    个棋子。 我们用跳跳棋来做一个简单的游戏: 棋盘上有 3 颗棋子, 分别在 a, b,
    c 这三个位置。 我们要通过最少的跳动把他们的位置移动成 x, y, z。 (棋子是
    没有区别的) 跳动的规则很简单, 任意选一颗棋子, 对一颗中轴棋子跳动。 跳动
    后两颗棋子距离不变。 一次只允许跳过 1 颗棋子。

        

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

    【输入格式】

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

    【输出格式】

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

    【样例输入】

    1 2 3
    0 3 5
    【样例输出】

    YES

    2提示

    100% 绝对值不超过 10^9


    刚开始看到这道题真的没什么想法,真是道神秘的好题啊(~)

    后来在草稿上自己画了几种状态,发现(!)每一种状态,只能发展出三种状态, 1.中间向左跳  2.中间向右跳 3.两边的某一个向中间跳(当然根节点状态不行)

    如果把一种状态疯狂地向中间折叠,会跳到一个平衡的状态,两边再也无法向中间跳了,这个状态其实就是根,而从这个状态向外发展出去,每次都只会发展出两种,所以发现这些状态构成了一棵二叉树,只要任意两种状态都能变成相同的根节点状态,那么它们一定可以相互转化(!)

    所以问题就转化成求树上两个不同节点的距离了。

    我先让两个节点跳到一个相同的深度,再二分距离,让这两个节点同时向上跳,最后得出答案。

    哦对了,向上跳(向内折叠)时发现可以用除法来加速,一下子可以折好大一段,没有必要每一次都是加法模拟(那样会超时的)

    (不知为什么我的代码很长)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 
      8 #define For(i,a,b) for(register int i=a;i<=b;++i)
      9 #define Re register 
     10 using namespace std;
     11 struct Bal{
     12     int x,y,z;
     13 }b1,b2,rb1,rb2,bx1,bx2;
     14 int tp1,tp2;
     15 inline void read(int &v){
     16     v=0; bool fg=0;
     17     char c=getchar(); if(c=='-')fg=1;
     18     while(c<'0'||c>'9'){c=getchar(); if(c=='-')fg=1;}
     19     while(c>='0'&&c<='9'){v=v*10+c-'0',c=getchar(); if(c=='-')fg=1;}
     20     if(fg)v=-v;
     21 }
     22 
     23 void getNT(Bal &b){ //使x,y,z有序 
     24     if(b.x>b.y)swap(b.x,b.y);
     25     if(b.x>b.z)swap(b.x,b.z);
     26     if(b.y>b.z)swap(b.y,b.z);
     27 }
     28 
     29 int ComeBack(Bal &b){ //跳到根节点 
     30     int stp=0;
     31      getNT(b);
     32     while(b.x+b.z!=b.y*2){
     33         int d1=b.y-b.x;
     34         int d2=b.z-b.y;
     35         if(d1<d2){
     36             int tp=d2/d1;
     37             if(d2%d1==0)tp--;
     38             b.x+=tp*d1;
     39             b.y+=tp*d1;
     40             if(b.x>b.y)swap(b.x,b.y);
     41             stp+=tp;
     42         }else{
     43             int tp=d1/d2;
     44             if(d1%d2==0)tp--;
     45             b.y-=tp*d2;
     46             b.z-=tp*d2;
     47             if(b.z<b.y)swap(b.z,b.y);
     48             stp+=tp;
     49         }
     50     }
     51     return stp;
     52 }
     53 
     54 bool QL(Bal a,Bal b){
     55     if(a.x==b.x&&a.y==b.y&&a.z==b.z)return 1;
     56     return 0;
     57 }
     58 
     59 Bal CheckandGo(Bal bl,int Lim){ //二分出可以向上跳的距离然后向上跳 
     60     Bal b=bl;
     61     int Lm=Lim;
     62     getNT(b);
     63     while(Lm){
     64         int d1=b.y-b.x;
     65         int d2=b.z-b.y;
     66         if(d1<d2){
     67             int tp=d2/d1; 
     68             if(d2%d1==0)tp--;
     69             if(tp>Lm)tp=Lm;
     70             b.x+=tp*d1;
     71             b.y+=tp*d1;
     72             if(b.x>b.y)swap(b.x,b.y);
     73             Lm-=tp;
     74         }else{
     75             int tp=d1/d2;
     76             if(d1%d2==0)tp--;
     77             if(tp>Lm)tp=Lm;
     78             b.y-=tp*d2;
     79             b.z-=tp*d2;
     80             if(b.z<b.y)swap(b.z,b.y);
     81             Lm-=tp;
     82         }
     83         if(Lm==0)break;
     84     }
     85     return b;
     86 }
     87 
     88 int main(){
     89 //    freopen("hop.in","r",stdin);
     90 //    freopen("hop.out","w",stdout);
     91     read(b1.x); read(b1.y); read(b1.z);
     92     read(b2.x); read(b2.y); read(b2.z);
     93 
     94     getNT(b1); getNT(b2);
     95     bx1=b1; bx2=b2;
     96     tp1=ComeBack(bx1); tp2=ComeBack(bx2);
     97     
     98     
     99     if(!QL(bx1,bx2)){
    100         printf("NO"); 
    101     }else{
    102         int bs=abs(tp1-tp2);
    103         int l=0,r=min(tp1,tp2),ff;
    104         
    105         if(tp1<tp2){//跳到同一深度 
    106             b2=CheckandGo(b2,bs);
    107         }else{
    108             b1=CheckandGo(b1,bs);
    109         }
    110         
    111         while(l<=r){ //二分 
    112             int m=(l+r)>>1;
    113             bx1=CheckandGo(b1,m);
    114             bx2=CheckandGo(b2,m);
    115             if(QL(bx1,bx2))ff=m,r=m-1;
    116             else l=m+1;
    117         }
    118         cout<<"YES"<<endl;
    119         cout<<bs+ff*2<<endl;
    120     }
    121     return 0;
    122 }
  • 相关阅读:
    linux下配置java环境及问题
    Chrome工具使用
    Ibatis的resultMap和查询数据的对应关系
    spring mvc接收数组
    PowderDesign的使用
    Android Runtime Stats
    [原创]ASM动态修改JAVA函数之函数字节码初探
    [原创]WB Android客户端架构总结:发WB工作队列设计
    [原创]Android Studio的Instant Run(即时安装)原理分析和源码浅析
    [原创]Android系统中常用JAVA类源码浅析之HashMap
  • 原文地址:https://www.cnblogs.com/HLAUV/p/9883140.html
Copyright © 2020-2023  润新知