跳跳棋

其实这道题并不是很难,但是确实不太好想啊。。。

题目大意:

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

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

我们仔细的剖析一下题意:

我们从题目中可知,一共只有三种移动方式:

1.中间的棋子往左跳

2.中间的棋子往右跳

3.两边离中间近的棋子往中间跳(因为如果是远的棋子的话就会跳过两个了。。。)

那么我们知道,如果不断进行第三步操作,最后一定会得到中间棋子到两边距离相等的情况,那么如果两种摆放方式经过这种迭代后,到中间距离相等,那么就代表他们是可以互相转换的,反之则不能。

那么我们就可以判断是否可以完成任务了,而且我们知道棋子看的是相对位置,那么a   b        c,将a跳到bc中间就等于a,b同时向右移ab的差值,但是我们发现每一次减速度太慢,所以我们大可以将每一次移动差值步改为移动另一个差值%这个差值步,想一想正确性?

那么,我们怎么计算需要多少步呢?由于我们知道每一次都有三种选择,那么如果我们从距离相等的情况开始拓展,那么就会有两种选择。也就是这些状态构成了一颗二叉树。

那么我们所求的答案就是树上两点间距离啦!

这个建一个树当然也可以,或者直接判断也行。。。

关于时间复杂度,由于取模运算和gcd比较类似,所以忽略常数影响,应该是log级别的:logx(x是给出的最大距离差)

最后,附上本题代码:

  1 #include<cstdio>
  2 #include<iostream>
  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     else
106     {
107         int dt=abs(temp1-temp2),l=0,r=min(temp1,temp2),ans;
108         if(temp1<temp2) c2=update(c2,dt);
109         else c1=update(c1,dt);
110         while(l<=r)
111         {
112             int mid=(l+r)>>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 }

 

转载于:https://www.cnblogs.com/yufenglin/p/10629165.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值