描述

小招喵喜欢在数轴上跑来跑去,假设它现在站在点n处,它只会3种走法,分别是:

1.数轴上向前走一步,即n=n+1 

2.数轴上向后走一步,即n=n-1 

3.数轴上使劲跳跃到当前点的两倍,即n=2*n

现在小招喵在原点,即n=0,它想去点x处,快帮小招喵算算最快的走法需要多少步?

输入描述:

小招喵想去的位置x

输出描述:

小招喵最少需要的步数

解题思路

首先给出几个显而易见的推论:

1、从0走到x,和从0走到-x,用的步数是相同的,因此只要考虑正数。

2、从0走到x的步数,和从x走到0是一样的,因此可以反向计算。

3、反向计算的情况下,按照贪心的思想,若x为偶数,那么直接除以2就是最优解,若x为奇数,则要考虑+1或者-1哪个更优秀,这也是本题的关键。

我的想法是,将x-1和x+1这两个数分别表示成二进制数,比较其中1的个数,个数越少的越优秀;若1的个数相同,那么取数字更小的x-1。

原因很简单,除以2的效率比±1的效率要高多了,所以应该让-1或+1后的数字末尾的0尽可能多,相应的,就是让1尽可能少。

举一个例子,若x = 23,那么将其变成22或者24,哪个才是最优解?分别列出来

22,11,10,5,4,2,1,0。 一共是8步。

24,12,6,3,2,1,0。 一共是7步。

而22的二进制数为10110,一共3个1;24的二进制数为11000,只有2个1,确实符合结论。

下面贴出c++代码。

#include <iostream>
using namespace std;

//计算x的二进制表示中包含1的个数
int count1(int x) {
    int res = 0;
    while (x) {
        if (x & 1) ++res;
        x >>= 1;
    }
    return res;
}

int main() {
    int x;
    cin >> x;
    if (x < 0) x = -x;
    int ans = 0;
    while (x) {
        if (x & 1) { //奇数的情况下比较-1和+1哪个更优秀
            if (count1(x - 1) <= count1(x + 1)) {
                --x;
            } else {
                ++x;
            }
        } else { //偶数的情况下直接除以2
            x >>= 1;
        }
        ++ans;
    }
    cout << ans;
}