其实这道题并不是很难,但是确实不太好想啊。。。
题目大意:
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。
我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
我们仔细的剖析一下题意:
我们从题目中可知,一共只有三种移动方式:
1.中间的棋子往左跳
2.中间的棋子往右跳
3.两边离中间近的棋子往中间跳(因为如果是远的棋子的话就会跳过两个了。。。)
那么我们知道,如果不断进行第三步操作,最后一定会得到中间棋子到两边距离相等的情况,那么如果两种摆放方式经过这种迭代后,到中间距离相等,那么就代表他们是可以互相转换的,反之则不能。
那么我们就可以判断是否可以完成任务了,而且我们知道棋子看的是相对位置,那么a b c,将a跳到bc中间就等于a,b同时向右移ab的差值,但是我们发现每一次减速度太慢,所以我们大可以将每一次移动差值步改为移动另一个差值%这个差值步,想一想正确性?
那么,我们怎么计算需要多少步呢?由于我们知道每一次都有三种选择,那么如果我们从距离相等的情况开始拓展,那么就会有两种选择。也就是这些状态构成了一颗二叉树。
那么我们所求的答案就是树上两点间距离啦!
这个建一个树当然也可以,或者直接判断也行。。。
关于时间复杂度,由于取模运算和gcd比较类似,所以忽略常数影响,应该是log级别的:logx(x是给出的最大距离差)
最后,附上本题代码:
1 #include2 #include 3 4 //Debug Yufenglin 5 #define debugj printf("Running\n"); 6 #define debugp1(x) printf("%d\n",x); 7 #define debugp2(x,y) printf("%d %d\n",x,y); 8 #define debugp3(x,y,z) printf("%d %d %d\n",x,y,z); 9 10 //Standfor Yufenglin 11 #define LL long long 12 #define LB long double 13 #define reg register 14 #define il inline 15 #define inf 1e8 16 #define maxn 1e5 17 18 using namespace std; 19 20 struct state 21 { 22 int x,y,z; 23 }; 24 state pre,now,c1,c2,ct1,ct2; 25 26 int abs(int x) 27 { 28 if(x<0) return -x; 29 return x; 30 } 31 void merge(state &w) 32 { 33 if(w.x>w.y) swap(w.x,w.y); 34 if(w.y>w.z) swap(w.y,w.z); 35 if(w.x>w.y) swap(w.x,w.y); 36 } 37 bool judge(state a,state b) 38 { 39 if(a.x==b.x&&a.y==b.y&&a.z==b.z) return 1; 40 return 0; 41 } 42 int find_father(state &w) 43 { 44 int step=0; 45 while(w.x+w.z!=2*w.y) 46 { 47 int s1=w.y-w.x,s2=w.z-w.y; 48 if(s1>s2) 49 { 50 int tep=s1/s2; 51 if(s1%s2==0) tep--; 52 w.y-=tep*s2; 53 w.z-=tep*s2; 54 merge(w); 55 step+=tep; 56 } 57 else 58 { 59 int tep=s2/s1; 60 if(s2%s1==0) tep--; 61 w.x+=tep*s1; 62 w.y+=tep*s1; 63 merge(w); 64 step+=tep; 65 } 66 } 67 return step; 68 } 69 state update(state w,int mid) 70 { 71 merge(w); 72 while(mid!=0) 73 { 74 int s1=w.y-w.x,s2=w.z-w.y; 75 if(s1>s2) 76 { 77 int tep=s1/s2; 78 if(s1%s2==0) tep--; 79 tep=min(tep,mid); 80 w.y-=tep*s2; 81 w.z-=tep*s2; 82 merge(w); 83 mid-=tep; 84 } 85 else 86 { 87 int tep=s2/s1; 88 if(s2%s1==0) tep--; 89 tep=min(tep,mid); 90 w.x+=tep*s1; 91 w.y+=tep*s1; 92 merge(w); 93 mid-=tep; 94 } 95 } 96 return w; 97 } 98 int main() 99 {100 scanf("%d%d%d%d%d%d",&pre.x,&pre.y,&pre.z,&now.x,&now.y,&now.z);101 merge(pre),merge(now);102 c1=pre,c2=now;103 int temp1=find_father(pre),temp2=find_father(now);104 if(judge(pre,now)==0) printf("NO\n");105 else106 {107 int dt=abs(temp1-temp2),l=0,r=min(temp1,temp2),ans;108 if(temp1 >1;113 ct1=update(c1,mid);114 ct2=update(c2,mid);115 if(judge(ct1,ct2)==1) ans=mid,r=mid-1;116 else l=mid+1;117 }118 printf("YES\n%d\n",dt+ans*2);119 }120 return 0;121 }