【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数组的原因之一。

    数组下标0234567891011121314151617
    char数组192A34578\00000000
    int数组00000000192A34578

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

    #include<cstdio>    //scanf()
    #include<cstring>   //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<cstdio>    //scanf()
    #include<cstring>   //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<cstdio>    //scanf()
    #include<cstring>   //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+0n+1n+2n+3n+4
    加数135281
    加数218253

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

    #include<cstdio>    //scanf()
    #include<cstring>   //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<cstdio>    //scanf()
    #include<cstring>   //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<cstdio>    //scanf()
#include<cstring>   //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++不使用公式和选择、循环求阶和

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值