【C++】每周一题——1024.2.21

题目

#题目
【问题描述】
若一个数(首位不为0)从左向右读和从右向左读都是一样,我们就称其为回文数。例
如,给定一个十进制数56,将56+65(即把56从右向左读),得到的121是一个回文串。
又如,十进制整数87:
STEP1: 87+78=165
STEP2: 165+561=726
STEP3: 726+627=1353
STEP4: 1353+3531=4884
在这里,是进行一次N进制的加法,上例用了最少四次得到回文数4884
写一个程序,将N进制数m,m的尾数上限为20。求最少几步可以得到回文数,如果在30
步以内不能得到回文数,输出“impossible”。
【输入格式】
一行,有空格隔开的两个数,n,m(m为正整数)
【输出格式】
也是一行,最少得到回文数得步数,若30步以内,得不到回文数,输出“impossible”。
【输入样例】
9 87
【输出样例】
6


分析

n进制下(尾数上限为20,即最高的那一位数为20(K)),输入一个数,将它不断地与自己反着读得的数相加,直到得数是回文数,最多循环30次,若得出,就输出“impossible”。


解答

步骤详解

  1. 框架先写上

    int main(){
        return 0;
    }
    

  2. 首先,输入数据,为了方便循环赋值,m先用char数组输入。
    为了方便后面进位,所以从后往前的把数据放入int数组。这也是不能直接循环输入到int数组的原因之一。

    数组下标 0 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
    char数组 1 9 2 A 3 4 5 7 8 \0 0 0 0 0 0 0 0
    int数组 0 0 0 0 0 0 0 0 1 9 2 A 3 4 5 7 8

    如果进制(n)大于10,就会出现大写字母;要先判断再赋值。

    #include    //scanf()
    #include   //strlen()
    int n, m[1024];
    char scan_m[1024];
    int main(){
        scanf("%d %s", &n, &scan_m);
        for(int i=0; i<strlen(scan_m); i++){
            char n=scan_m[strlen(scan_m)-1-i];
            if(n>='0' && n<='9'){
                m[1023-i]=n-'0';
            }else{
                m[1023-i]=n-'A'+10;
            }
        }
        return 0;
    }
    

  3. 为了方便后续的操作,我们先写一个自定义函数求当前数组m的位数(不算上前面的0

    #include    //scanf()
    #include   //strlen()
    int n, m[1024];
    char scan_m[1024];
    int intlen(int n[]){
        int len;
        for(len=0; n[len]==0; len++);
        return 1024-len;
    }
    int main(){
        scanf("%d %s", &n, &scan_m);
        for(int i=0; i<strlen(scan_m); i++){
            char n=scan_m[strlen(scan_m)-1-i];
            if(n>='0' && n<='9'){
                m[1023-i]=n-'0';
            }else{
                m[1023-i]=n-'A'+10;
            }
        }
        return 0;
    }
    

  4. 后面我们就要做加法了,现在我们先把循环30次写上。

    #include    //scanf()
    #include   //strlen()
    int n, m[1024], temp[1024];
    char scan_m[1024];
    bool hw;
    int intlen(int a[]){
        int len;
        for(len=0; a[len]==0; len++);
        return 1024-len;
    }
    int main(){
        scanf("%d %s", &n, &scan_m);
        for(int i=0; i<strlen(scan_m); i++){
            char n=scan_m[strlen(scan_m)-1-i];
            if(n>='0' && n<='9'){
                m[1023-i]=n-'0';
            }else{
                m[1023-i]=n-'A'+10;
            }
        }
        for(int i=1; i<=30; i++){}
        return 0;
    }
    

  5. 接下来,开始做加法(和进位)。
    其实第二个加数没有必要新建数组(得数还是要的),我们可以直接数组m的第(n+)i位加上数组m的第倒数第i位(下图的n指该数组前面空出的0的数量,n=1024-intlen())。

    数组下标 n+0 n+1 n+2 n+3 n+4
    加数1 3 5 2 8 1
    加数2 1 8 2 5 3

    十进制加法是逢十进一,n进制加法便是逢n进一。尽管n大于10也没关系。

    #include    //scanf()
    #include   //strlen()
    int n, m[1024], temp[1024];
    char scan_m[1024];
    int intlen(int a[]){
        int len;
        for(len=0; a[len]==0; len++);
        return 1024-len;
    }
    int main(){
        scanf("%d %s", &n, &scan_m);
        for(int i=0; i<strlen(scan_m); i++){
            char n=scan_m[strlen(scan_m)-1-i];
            if(n>='0' && n<='9'){
                m[1023-i]=n-'0';
            }else{
                m[1023-i]=n-'A'+10;
            }
        }
        for(int i=1; i<=30; i++){
    	    for(int i=0; i<intlen(m); i++){
    	        temp[1024-intlen(m)+i]=m[1024-intlen(m)+i]+m[1023-i];
    	        if (temp[1024-intlen(m)+i]>=n){
    	            temp[1024-intlen(m)+i]-=n;
    	            temp[1024-intlen(m)+i-1]++;
    	        }
    	    }
    	    for(int i=0; i<intlen(temp); i++){
    	        m[1024-intlen(temp)+i]=temp[1024-intlen(temp)+i];
    	    }
    	}
        return 0;
    }
    

  6. 现在,判读回文数就够了。如果是回文数,就输出当前次数,然后可以直接结束程序了;否则,如果大循环30了次后都没有得出回文数,就输出“impossible”。
    老样子,直接判断数组m的第(n+)i位是否等于数组m的第倒数第i位即可,而且,为了保证速度,这里只需要遍历一半就够了。

    #include    //scanf()
    #include   //strlen()
    int n, m[1024], temp[1024];
    char scan_m[1024];
    bool hw;
    int intlen(int a[]){
        int len;
        for(len=0; a[len]==0; len++);
        return 1024-len;
    }
    int main(){
        scanf("%d %s", &n, &scan_m);
        for(int i=0; i<strlen(scan_m); i++){
            char n=scan_m[strlen(scan_m)-1-i];
            if(n>='0' && n<='9'){
                m[1023-i]=n-'0';
            }else{
                m[1023-i]=n-'A'+10;
            }
        }
        for(int i=1; i<=30; i++){
            for(int i=0; i<intlen(m); i++){
                temp[1024-intlen(m)+i]=m[1024-intlen(m)+i]+m[1023-i];
                if(temp[1024-intlen(m)+i]>=n){
                    temp[1024-intlen(m)+i]-=n;
                    temp[1024-intlen(m)+i-1]++;
                }
            }
            for(int i=0; i<intlen(temp); i++){
                m[1024-intlen(temp)+i]=temp[1024-intlen(temp)+i];
            }
            hw=true;
            for(int i=0; i<=intlen(m)/2; i++){
                if(m[1024-intlen(m)+i]!=m[1024-1-i]){
                    hw=false;
                }
            }
            if(hw){
                printf("%d", i);
                return 0;
            }
        }
        printf("impossible");
        return 0;
    }
    


答案

#include    //scanf()
#include   //strlen()
int n, m[1024], temp[1024];
char scan_m[1024];
bool hw;
int intlen(int a[]){
    int len;
    for(len=0; a[len]==0; len++);
    return 1024-len;
}
int main(){
    scanf("%d %s", &n, &scan_m);
    for(int i=0; i<strlen(scan_m); i++){
        char n=scan_m[strlen(scan_m)-1-i];
        if(n>='0' && n<='9'){
            m[1023-i]=n-'0';
        }else{
            m[1023-i]=n-'A'+10;
        }
    }
    for(int i=1; i<=30; i++){
        for(int i=0; i<intlen(m); i++){
            temp[1024-intlen(m)+i]=m[1024-intlen(m)+i]+m[1023-i];
            if(temp[1024-intlen(m)+i]>=n){
                temp[1024-intlen(m)+i]-=n;
                temp[1024-intlen(m)+i-1]++;
            }
        }
        for(int i=0; i<intlen(temp); i++){
            m[1024-intlen(temp)+i]=temp[1024-intlen(temp)+i];
        }
        hw=true;
        for(int i=0; i<=intlen(m)/2; i++){
            if(m[1024-intlen(m)+i]!=m[1024-1-i]){
                hw=false;
            }
        }
        if(hw){
            printf("%d", i);
            return 0;
        }
    }
    printf("impossible");
    return 0;
}

尾声(鸡汤)

看似很难操作的n进制加法其实理解了本质一点都不难,有没有用到特殊的数据类型。所以,我们做一件事要知其意,理解本质,才能活学活用。


大家还可以看看这道题《C++不使用公式和选择、循环求阶和》

你可能感兴趣的:(编程,数学,c++,算法,数据结构,开发语言)