标签:快速 http turn 连续 mamicode 分析 完成 span tput
Descrption
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。
我们用跳跳棋来做一个简单的游戏:棋盘上有 \(3\) 颗棋子,分别在 \(a,b,c\) 这三个位置。我们要通过最少的跳动把它们的位置移动成 \(x,y,z\)。(棋子是没有区别的)
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过 \(1\) 颗棋子。
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
Input
Output
Sample Input
1 2 3
0 3 5
Sample Output
YES
2
Hint
分析
Code
#include <bits/stdc++.h>
const int Inf=0x3f3f3f3f;
struct Node{
int x,y,z;
void init(){
scanf("%d%d%d",&x,&y,&z);
if(x>y)std::swap(x,y);
if(x>z)std::swap(x,z);
if(y>z)std::swap(y,z);
}
}a,b,p,q;
int step,k;
bool Equal(Node u,Node v){
return u.x==v.x && u.y==v.y && u.z==v.z;
}
Node GetRoot(Node t,int s){//s表示往上跳多少步,找根时s==Inf
for(step=0;s;step+=k){
int d1=t.y-t.x,d2=t.z-t.y;
if(d1==d2) return t;//两边倒中间的距离相等
if(d1<d2){//x以y为轴往右跳
k=std::min((d2-1)/d1,s);//d2-1是避免d2是d1的倍数,跳重合了
t.x+=k*d1;t.y+=k*d1;s-=k;//跳的过程相当于x,y向右平移了k*d1
}
else{//z以y为轴向左跳
k=std::min((d1-1)/d2,s);//k表示跳的次数
t.y-=k*d2,t.z-=k*d2,s-=k;
}
}
return t;
}
void Solve(){
a.init();b.init();//读入并排序
p=GetRoot(a,Inf);int step1=step;//a状态往内跳直到距离相等即到根
q=GetRoot(b,Inf);int step2=step;//b状态往内跳直到距离相等即到根
if(!Equal(p,q)){//根的状态不一样,无论如何跳都不可能重合
printf("NO\n");return;
}
if(step1<step2){//a状态离根近就交换
std::swap(a,b);
std::swap(step1,step2);
}
a=GetRoot(a,step1-step2);//a状态往内跳,直到a,b离根距离一样,类似lca
int l=0,r=step2,mid;//二分找到a,b的最近公共祖先
while(l<r){
mid=(l+r)>>1;
if(Equal(GetRoot(a,mid),GetRoot(b,mid))) r=mid;
else l=mid+1;
}//跳出循环时,往上跳l步正好是最近公共祖先
printf("YES\n%d\n",(l<<1)+step1-step2);
}
int main(){
Solve();
return 0;
}
标签:快速 http turn 连续 mamicode 分析 完成 span tput
原文地址:https://www.cnblogs.com/hbhszxyb/p/13371281.html