Sicily 1028 Hanoi Tower Sequence

31 篇文章 0 订阅
/*
【题目大意】
汉诺塔,将其移动的每一步的盘号列出作为序列,求第p步需要移动的盘的盘号
序列如下:1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1.... 
【解决方案】
输入的p将达到10^100,使用string接收 
注意每个case之间要多一个空行 
1、移动盘子的规律:把前n-1个盘子移到二号柱子,移动n号盘,然后再移动前n-1个盘到三好柱子即可
    移动一个盘子要1步,移动k(k>1)个盘子要f(k)=f(k-1)+1+f(k-1)=2^k-1步
    也即在序列中,当p=2^k时,f(p)=k+1,并且这是k+1号盘子的第一次出现; 
2、直观上看,如果某一位数字是k,那么它的前2^(k-1)-1个数和后2^(k-1)-1个数是一样的
3、根据第二条,对于某个p,如果2^k < p < 2(k+1),那么f(p)和f(p-2^k)是相等的
    这里如果根据二进制来看:把p化成二进制数,假设现在p里有超过1个位为1,设最高位为k,
    则在2^k步前和2^k步后对称,因此第p步移的盘子与第p-2^k步移的盘子一样。
4、根据第三条,一直往前循环,从二进制的角度看,p排在高位的1一个个被减掉,直到p里只有1个位为1,
    设此时p=2^m,对应的二进制数是1后面跟着m个0,则此步移动的是第m+1个盘子。
    直观上看,这是第m+1号盘子的第一次移动(结合第一条),而这个m+1就是我们想要的结果
5、可以得知:如果p1=11010101011101010110111000,根据第三条,可以一直往前追朔到p2=1000,并且f(p1)=f(p2)
    从第一条我们可以知道f(p1)=f(p2)=f(2^3)=3+1=4
6、由以上可得:对于p,如果其二进制表示时结尾0的数量为m,那么第p位就是m+1,
    我们知道,一个整数除以2时表现为二进制右移一位,
    所以:对于p,求得其可整除2的次数m,即可得结果为m+1
7、于是这一题就变成了吃果果的大数求余了。 

终于写完,希望以后的自己能看懂吧
*/
/*
Run Time: 0.1secs
Run Memory: 312KB
*/

#include <iostream>
#include <string>

using namespace std;

//大数求余 
inline int Mod(const string& a, const int& b){
    int result = 0;
    for(int i=0; i<a.length(); i++){
        int num = result*10 + (a[i]-'0');
        result = num % b;
    }
    return result;
}

//不完美的大数除法,没有判断0,且求得的结果会有前缀0 
inline string Div(const string& a, const int& b){
    int buf = 0;
    string result = "";
    for(int i=0; i<a.length(); i++){
        int num = buf*10 + (a[i]-'0');
        buf = num % b;
        result += (num/b + '0');   //因为可以肯定只有一位,可以直接用这种方法得到char 
    }
    return result;
}

int compute(string num){
    int result = 1;
    while(1){
        if(Mod(num, 2) == 0){
            result++;
            num = Div(num, 2);
        }else{
            return result;
        }
    }
}

int main()
{
    int T;
    cin >> T;
    int TT = T;
    string num; 
    
    while (T-->0){
        cin >> num;
        
        if(TT-T != 1) 
            cout << endl; 
    
        cout << "Case " << TT-T << ": " << compute(num) << endl; 
    }

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值