「青训营 X 码上掘金」主题创作之寻友之旅 ----纯逻辑硬解!

48 阅读2分钟

当青训营遇上码上掘金

主题 3:寻友之旅 | C++ 菜鸟逻辑硬解版本!

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

说明:本人算法菜鸟一枚,欢迎路过大神指正~

下面是代码解决方案

初代版本解法(错误解法):

不想看错误初代版本的小伙伴可以看下面的正解。

思路

①首先判断n与k的值,有下面两种情况

  • 当n>k时,那么小青只能是向左边慢慢移动,只能(X-1)移动,所以小青最快到达小码的地方需要的最短时间 minTime = n-k.
  • 当n<k时,小青向右边走,小青可以选择两种走法,在这个解法中,我选择的是,使用一个while循环来判断小青 n<=k ,当在这个范围内,小青可以每次行走都是2X的方式,当while循环判断n<=k这个条件不满足的时候,我们就跳出循环,此时我们知道n和minTime都多执行了一次操作,在下面的代码中,使用if条件判断(n!=k),在if语句中书写n = n/2,minTime = minTime - 1,剩下的minTime则是选择走路到达,故最后的minTime = minTime + temp.

代码

using namespace std;
#include<iostream>

int main(){
	int minTime = 0;
    int n, k;
    cin >> n >> k;
    cout<<"n:"<<n<<endl;
    cout<<"k:"<<k<<endl;
    if(n>k){
    //如果n>k的话,不能坐公交,因为公交不能倒退,所以只能选择步行。
	minTime = n - k;
	}else{
	//n<k 的情况下,可以选择坐公交或者步行
	//先选择坐公交 是节省时间的方式
	while(n <= k){
		//这种情况包含n恰好等于k的情况 
		n = n*2;
		minTime++;
		if(n == k){
			cout<<"最短时间为:"<<minTime<<endl;
			return 0;
			}
		} 
		if(n != k){
			n = n/2;
			minTime = minTime-1;
			int temp = k - n;//剩余的部分选择步行到达
			minTime = minTime + temp; 
		}
	}
	cout<<"最短时间为:"<<minTime<<endl;
//此方法是不严谨的方法
//案例① 输入 1 8 
//	   输出 3    -----正确答案 
//案例② 输入 1 14 
//	     输出 9  -----错误答案
//错误原因:最短时间应该是5  过程是1-2-4-8-7-14 ,花费5秒钟 
//  
    return 0;
}

初代代码版本参考这位同学的,不过他的也是错误的。 juejin.cn/post/718778…

最终成功版本:

思路 ①首先判断n与k的值,有下面两种情况(关键看n<k时的操作)

  • 当n>k时,那么小青只能是向左边慢慢移动,只能(X-1)移动,所以小青最快到达小码的地方需要的最短时间 minTime = n-k.

  • 当n<k时,开始我先是将n与k的值进行处理,将n的值和k的值从奇数变成偶数,方便我们的操作。

    A.处理n(左端):当n%2!=0时,表示n是奇数,我们需要将n进行处理,变为偶数,此时操作为:n = n * 2;,minTime = minTime+1;在这个处理操作的if语句中同时在添加两个if判断,如果if(n==k),就直接输出cout<<minTime<<endl;如果(n>k),说明n * 2之后越界了,n = n/2;minTime = k-n;然后直接输出minTime就好。

    B.处理k(右端):如果k是奇数-1,然后再/2 ,下面通过一个if(n*2<=k)来判断并且保证k是在n的右边的,接下来再判断k是奇数还是偶数,然后执行相应的操作,若是奇数k-1,若是偶数k/2,慢慢逼近n最终得到结果!

整体的算法思想 从k(右端开始倒退),k每次除以2,当k是奇数则-1,minTime++;然后k/2继续操作,目的就是遇到奇数就变偶数,遇到偶数除以二,以此类推,慢慢从右端逼近左端,即k慢慢逼近n,最后求出来的minTime就是最短时间。同时,如果左端n开始是奇数,那么直接给他×2变偶数就行,当成新的n,minTime同时++即可!

代码

using namespace std;
#include<iostream>

int main(){

    int n, k;
    cin >> n >> k;
    cout<<"n:"<<n<<endl;
    cout<<"k:"<<k<<endl;
 	int minTime = 0;//最少时间
        if (n > k) {
            //如果n>k的话 就说明不能坐公交,因为公交不能倒退,所以只能选择步行。
            minTime = n - k;
        } else if (n < k) {
            //如果n<k的话 就说明可以公交或者步行
           //先处理左端 例如n是奇数的话,就给他*2,变为偶数
           if(n%2!=0){
           	n = n*2; //之后计算距离就从n*2开始计算 minTime+1就行 
           	minTime = minTime+1; 
		   	if(n==k){
		   		cout<<minTime<<endl; 
		   		return 0;
			   }
			else if(n>k){ //n*2之后越界了 n比k大 
				//撤回刚才*2的操作
				n = n/2;
				minTime = k-n; 
				cout<<minTime<<endl; 
		   		return 0;
			} 
		   }
		   
		   //右端k也要处理,如果k是奇数-1,然后再/2 	   
		   while(n!=k){
		   	if(n*2<=k){
		   		if(k%2!=0){
			   	k = k-1;
			   	minTime++;
			   	}
			   	else{
			   	k = k/2;
			   	minTime++;
				}
			   }
			else{
			   	minTime =minTime + k - n;
			   	break; 
			   } 
		   }
			cout<<minTime<<endl; 
		   		return 0;   
		   
        }
//		cout<<"最短时间:"<<minTime<<endl; 
    return 0;
}