zoukankan      html  css  js  c++  java
  • [bzoj2144]: 跳跳棋 2017-06-02 15:53 42人阅读 评论(0) 收藏

    2144: 跳跳棋

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 689  Solved: 326
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    1 2 3
    0 3 5

    Sample Output

    YES
    2


    【范围】
    100% 绝对值不超过10^9

    思路
    bzoj 2144 跳跳棋 2017.6.2 by xlj 
    难题一道 很不好想 
    从题目条件中看似6种状态 
    但因为一个棋子不能跳过两个棋子
    如果 1 4 10 此时右边的就不能跳 因为越过两个棋子了 
    所以只有三种(中间的可以跳两边&离中间棋子距离近的可以跳) 
    可以把这三种状态看成一棵树
    此时可以设棋子为x,y,z; 
    设y-x=t1 z-y=t2
    当t1==t2的时候就没有办法跳了 这个状态就是树根了
    如果t1<t2 最多跳(t2-1)/t1步  t2>t1 同理 
    然后类似gcd的方法求树根 (t1,t2)->(t1-t2,t2) 
    从给出的a1,b1,c1往上推出数根
    a2,b2,c2也是一样
    如果树根不同 代表不能完成 输出NO
    如果相同 先把两个状态深度调为一样 再往上找(LCA) 

    这里用的是二分法找 

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #define inf 1000000000
    using namespace std;
    int a[5],b[5];
    struct node{
    	int a[5];
    };
    int tmp,ans;
    node cal(int *a,int k)//在树上往上跳的 函数 k是跳的步数 跳到根就结束 
    {
    	node ans;
    	int t1=a[2]-a[1];int t2=a[3]-a[2];
    	for(int i=1;i<=3;i++) ans.a[i]=a[i];
    	if(t1==t2) return ans;
    	if(t1<t2){
    		int t=min(k,(t2-1)/t1);
    		k-=t;tmp+=t;
    		ans.a[2]+=t*t1;ans.a[1]+=t*t1;
    	}
    	else {
    		int t=min(k,(t1-1)/t2);
    		k-=t;tmp+=t;
    		ans.a[2]-=t*t2;ans.a[3]-=t*t2;
    	}
    	if(k) return cal(ans.a,k);
    	else return ans;
    }
    bool operator !=(node xx,node yy){//重载!比较结构体 
    	for(int i=1;i<=3;i++) if(xx.a[i]!=yy.a[i]) return 1;
    	return 0;
    }
    int main(){	
    	for(int i=1;i<=3;i++)	scanf("%d",&a[i]);
    	for(int i=1;i<=3;i++) 	scanf("%d",&b[i]);
    	sort(a+1,a+4);	sort(b+1,b+4);
    	node t1=cal(a,inf);int d1=tmp;tmp=0;
    	node t2=cal(b,inf);int d2=tmp;tmp=0;
    	//往上找 找到最上面 y-x==z-y 的树根 
    	if(t1!=t2) {
    		puts("NO");return 0;	
    	}
    	if(d1>d2)
        {
    		swap(d1,d2);
    		for(int i=1;i<=3;i++)swap(a[i],b[i]);
        }
        ans=d2-d1;//深度大的就往上调 
        t1=cal(b,ans);
        for(int i=1;i<=3;i++) b[i]=t1.a[i];
        int l=0,r=d1;
        while(l<=r)//二分法找LCA 
        {
    		int mid=(l+r)>>1;
    		if(cal(a,mid)!=cal(b,mid))l=mid+1;//不等就网上找 
    		else r=mid-1;//如果相等了 还可能在答案那个节点的下面 
        }
        puts("YES");
        printf("%d",ans+2*l);
        return 0;
    }



  • 相关阅读:
    字串符相关 split() 字串符分隔 substring() 提取字符串 substr()提取指定数目的字符 parseInt() 函数可解析一个字符串,并返回一个整数。
    表单select相关
    createElement() 创建元素 appendChild()添加元素
    css
    docker基本操作
    redis安装及基本操作
    MongoDB安装 基本操作
    printf输出参数的顺序
    静态库与动态库的制作
    linux下ls、split、readlink、iconv命令
  • 原文地址:https://www.cnblogs.com/xljxlj/p/7183629.html
Copyright © 2011-2022 走看看