• 1028. Hanoi Tower Sequence


    1028. Hanoi Tower Sequence

    Constraints

    Time Limit: 1 secs, Memory Limit: 32 MB

    Description

    Hanoi Tower is a famous game invented by the French mathematician Edourard Lucas in 1883. We are given a tower of n disks, initially stacked in decreasing size on one of three pegs. The objective is to transfer the entire tower to one of the other pegs, moving only one disk at a time and never moving a larger one onto a smaller. 

    The best way to tackle this problem is well known: We first transfer the n-1 smallest to a different peg (by recursion), then move the largest, and finally transfer the n-1 smallest back onto the largest. For example, Fig 1 shows the steps of moving 3 disks from peg 1 to peg 3.

    Now we can get a sequence which consists of the red numbers of Fig 1: 1, 2, 1, 3, 1, 2, 1. The ith element of the sequence means the label of the disk that is moved in the ith step. When n = 4, we get a longer sequence: 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1. Obviously, the larger n is, the longer this sequence will be.
    Given an integer p, your task is to find out the pth element of this sequence.

    Input

    The first line of the input file is T, the number of test cases.
    Each test case contains one integer p (1<=p<10^100).

    Output

    Output the pth element of the sequence in a single line. See the sample for the output format.
    Print a blank line between the test cases.

    Sample Input

    4
    1
    4
    100
    100000000000000

    Sample Output

    Case 1: 1
     
    Case 2: 3
     
    Case 3: 3
     
    Case 4: 15

    Problem Source

    ZSUACM Team Member

    // Problem#: 1028
    // Submission#: 2346268
    // The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
    // URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
    // All Copyright reserved by Informatic Lab of Sun Yat-sen University
    #include<iostream>
    #include<cmath>
    #include<string>
    using namespace std;
    
    bool diff(string a,string b){
        int lena=a.size();
        int lenb=b.size();
        if(lena<lenb)
            return true;
        else if(lena == lenb){
            int i;
            for(i=0;i<lena;i++){
                if(a[i]<b[i]){
                    return true;
                }
                else if(a[i]==b[i]){
                }
                else{
                    return false;
                }
            }
        }
        else
            return false;
        return false;
    }
    string add(string a,string b){
        string temp;
        int lena=a.size();
        int lenb=b.size();
        int x,y;
        x=lena;
        y=lenb;
        if(x>y){
            temp='0'+a;
            int i=0;
            int lent=temp.size();
            for(i=1;i<=lenb;i++){
                temp[lent-i-1]=((temp[lent-i]-'0')+(b[lenb-i]-'0'))/10+temp[lent-i-1];
                temp[lent-i]=((temp[lent-i]-'0')+(b[lenb-i]-'0'))%10+'0';
                
            }
        }
        else{
            temp='0'+b;
            int lent=temp.size();
            int i=0;
            for(i=1;i<=lena;i++){
                temp[lent-i-1]=((a[lena-i]-'0')+(temp[lent-i]-'0'))/10+temp[lent-i-1];
                temp[lent-i]=((a[lena-i]-'0')+(temp[lent-i]-'0'))%10+'0';
               
            }
        }
        int lent=temp.size();
        int i=0;
        while(temp[i]=='0'){
            i++;
        }
        temp.erase(temp.begin(),temp.begin()+i);
        return temp;
    }
    
    string pluss(string a,string b){
        string temp;
        int lena=a.size();
        int lenb=b.size();
        int x=lena,y=lenb;
        int key;
        for(key=1;key<=y;key++){
            if(a[lena-key]>=b[lenb-key]){
                temp=(char)(a[lena-key]-b[lenb-key]+'0')+temp;
            }
            else if(a[lena-key-1]!='0'){
                a[lena-key-1]=a[lena-key-1]-1;
                temp=(char)(a[lena-key]-b[lenb-key]+'0'+10)+temp;
            }
            else{
                int i=1;
                while(a[lena-key-i]=='0'){
                    i++;
                }
                a[lena-key-i]=a[lena-key-i]-1;
                i--;
                while(i>=1){
                    a[lena-key-i]='9';
                    i--;
                }
                temp=(char)(a[lena-key]-b[lenb-key]+'0'+10)+temp;
            }
        }
        int lent=temp.size();
        int i=0;
        while(temp[i]=='0'){
            i++;
        }
        temp.erase(temp.begin(),temp.begin()+i);
        return temp;
    }
    
    int getCase(string p){
        int i=0;
        string temp;
        temp=temp+'1';
        string front;
        while(diff(temp,p)){
            front=temp;
            temp=add(temp,temp);
            i++;
        }
        if(temp==p){
            return i+1;
        }
        else{
            p=pluss(p,front);
            return getCase(p);
        }
    }
    
    int main(){
        int n;
        cin>>n;
        int i=0;
        while(n--){
            string p;
            i++;
            cin>>p;
            if(n==0){
                cout<<"Case "<<i<<": "<<getCase(p)<<endl;
            }
            else{
                cout<<"Case "<<i<<": "<<getCase(p)<<endl<<endl;
            }
        }
        return 0;
    }                                 
    首先是要找规律,然后是大精度加减法以及比较大小的问题,大精度的那些函数是用string实现的。

    至于规律,我们可以简单的写下钱16次操作,我们会发现,当操作次数为2的(0,1,2,3....)次方的时候,对应操作的disk序号一定是第一次出现(1,2,3,4...),而且为操作次数加1,另外你会发现操作数为2的(0,1,2,3....)次方的时候下一位一定从disk1开始重复前面的所有步。

    所以我们可以找到离操作数最近的那个2的幂,然后把操作数减去2的幂得到的值赋值给操作数,再用递归的方法求出答案。方法仅供参考。

  • 相关阅读:
    前端面试:Vue.js常见的问题
    Web前端攻击方式及防御措施
    JavaScript代码规范
    bind、apply、call的理解
    Markdown标记语言简介及使用方法
    github个人主页的建立
    深度理解“高内聚低耦合”
    私有云与公有云的区别
    响应式网页设计
    redis和mongodb比较
  • 原文地址:https://www.cnblogs.com/riskyer/p/3400479.html
Copyright © 2020-2023  润新知