题目为,小明是一个快递员,在一座高楼中送外卖,此时他处于第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;
}