+1、-1还是*2(送外卖的最短时间)

题目为,小明是一个快递员,在一座高楼中送外卖,此时他处于第N层,他想要到达M层,每分钟小明可以选择步行上一层楼或者下一层楼或者乘电梯到达2*N的楼层,确保0<N<=M<100000.问小明最快到达M层的时间

解题思路:

以(3,30)为例
要以最快的速度到达目标楼层,乘2的方式肯定是首选
每次都判断当前楼层*2以后如果再通过+1、-1的步数走到目标楼层的总时间,
以及当前楼层直接+1、-1到目标楼层的总时间,如果前者快,先选择前者。(3-6-12-24)
无法选择*2后,比较当前楼层和目标楼层的差次dif(30-24),
但是其中dif的差值可以以二进制来看,例中dif=6=110(B),之前一共乘了3次,如果把最后的dif直接按每次+-1走需要六步,但是如果+-1的操作在最后一次乘法之前,即可以完成翻倍的效果,例如dif=6,则在第二次和第三次乘法前+1,即为最快方式,故总次数应为3(乘法次数)+2(插入的加法次数)=5;
特殊情况,以(17,29)为例,在此例中,乘法次数为1,但是dif=5=101(B),
那么这dif应尽量加在第一次乘法前以减少次数,总次数为1(乘法)+4/2(放在乘法前的)+1(最后一步)=4;

/********************************分界线**********************************/
在提出上述的思想后,我认为已经万事俱备,但是中午午睡的时候,发现还有一种特殊情况,这就是当dif分解成的二进制,
存在连续多个1的情况,例如当dif=7=0111(B),如果此前乘法的次数能够满足将dif的每一位放至不同的乘法次序前,那么很容易
看出还需要三步,但是换个思路,如果我乘法的次数足够,我将dif=7改写为dif=8-1,情况就变得不一样,我只需在倒数第三次乘法前+1,
在最后一次再-1,同样完成了dif=7的操作,但是此时加减次数仅为2,这意味着,凡是连续的1超过三次以上的,只要乘法次数满足,
我们都可以只走两步,这使得该算法更完善。

当然如果有其他小伙伴看到代码有bug,或者觉得我的算法不够好或者有漏洞,都可以跟我讨论或者留言,一起交流才能共同进步。

using namespace std;
#include<algorithm>
#include<iostream>
void lesstime(int *nowfloor, int endfloor, int*moves)
{
	int nf;
	int mov;
	/****接收参数***/
	nf = *nowfloor;
	mov = *moves;
	int dif1 = 0, dif2 = 0;
	dif1 = abs(endfloor - nf*2 + 1);//选择现在的楼层*2的方式,剩下的步数如果只能+、-1,那么现所需的总时间为dif1;
	dif2 = abs(endfloor - nf);//选择现在的楼层+、-1的方式走到目标楼层,现在所需的总时间;
	if (dif1 < dif2)//选择*2的方式比直接走到目标楼层更快
	{
		nf *= 2;
		mov++;
	}
	else//如果已经不能*2,剩下的路径按+、-1来计算
	{
		int multime = 0, maxmove,temp;
		if (mov > 0)
		{
			multime = mov;//先前的移动都是乘法,统计共乘了几次;
			temp = multime+1;
			maxmove = pow(2, multime);//如果总共乘了n此,如果在第一次乘法前+、-1,最后可以偏差的步数为2的n次方
			
			int addtimes = 0;
			while (dif2 != 0 && multime != -1)
			{
				int bit0 = 0;
				bit0 = dif2 & 0x01;
				if (bit0 == 1)
				{
					mov++;
					addtimes++;
				}
				else
				{
					if (addtimes >= 3);
					mov = mov - addtimes + 2;
					addtimes = 0;
				}

				dif2 = dif2 >> 1;
				multime--;
			}
			if (addtimes >= 3)
				mov = mov - addtimes + 2;
			if (dif2 != 0)
			{
				dif2 <<= temp;
				mov += dif2 / maxmove;
			}
		}
		else
		{
			mov = dif2;
		}
		nf = endfloor;
	}
	if (nf != endfloor)
	{
		lesstime(&nf, endfloor, &mov);//未到目标楼层,进入下一次迭代
	}
	*moves = mov;
}
int main()
{
	int ans = 0;
	int startfloor,desfloor;
	cin >> startfloor >> desfloor;
	
	lesstime(&startfloor, desfloor, &ans);
	
	cout << ans << endl;
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值