C语言 BC158 [NOIP1999]回文数题解(含多个示例)

目录

问题描述

示例(可直接复制)

示例1

示例2

示例3

示例4

示例5

要求分析

实现步骤

1.判断一个数是否为回文数

2.进制转换

3.转成十进制后相加

完整代码



问题描述

若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。

例如:给定一个10进制数56,将56加65(即把56从右向左读),得到121是一个回文数。

又如:对于10进制数87:

STEP1:87+78  = 165                  STEP2:165+561 = 726

STEP3:726+627 = 1353                STEP4:1353+3531 = 4884

在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884。

写一个程序,给定一个N(2<=N<=10或N=16)进制数M(100位之内),求最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出“Impossible!”

进制N>10时,使用大写'A'字母表示10,'B'表示11,...,'E'表示15

输入描述:

两行,分别为N,M

输出描述:

STEP=ans

示例(可直接复制)

写这道题的时候,最大的问题似乎并不在于代码如何编写,而是

不知道自己写的对不对!!!

因为自己淋过雨,就要(把别人的伞撕烂)给别人撑伞

所以,在这里提供了多个示例,基本涵盖了所有情况,另外还附上了可能出现的错误,大多是我踩过的坑,不整理不知道,一整理,妈呀,这么多……希望以后认真全面地思考!!

有了这些例子,妈妈再也不用担心我写完代码不知道自己写的对不对啦!

示例1

输入:

9
87

输出:
STEP=6

示例2

输入:

16
AC27

输出:
STEP=6

注意:
只有16进制的1-9处理方式不变,只有A-Z特殊处理!!

示例3

输入:

8
45

输出:
STEP=1

示例4

输入:

2
1001101

输出:
Impossible!

注意:

当step>30之后要break跳出,不然时间太长,如果在oj中做,可能超时。

示例5

输入:

10
98

输出:
STEP=24

注意:

十进制要特殊处理,如果不特殊处理,0不会被算进去(详情见下方分析)

要求分析

        这道题要求的是一个n进制数最少经过几步可以得到回文数,理解题目后可以发现,题并不难,但是要考虑的细节比较多。

        代码的重点一方面是如何判断回文数,另一方面是判断后发现若不是回文数,相加的时候怎么处理。

        我用的方法是将输入存在char数组中(考虑到可能有16进制数输入,需要处理A-Z,不能用long long或者int数组存),题目说n进制数在100位之内,所以char数组的大小应该稍大于100。

        要理解n进制最少经过几步可以得到回文数,可以先思考如果是一个十进制数,怎么求出得到回文数的最少步数。

        如果是十进制数,步骤如下:

        (1).求出输入的数组m的长度,判断输入是否是回文数。

        (2).定义step变量记录次数,如果step>30,跳出

        (3).如果m不是回文数,将步数step++,再把m和它倒置的数相加后重新赋给m,之后跳回(1)重新判断

        (4).当m是回文数或step>30时,跳出while循环,判断输出步数(step<30)还是输出“Impossible!”(step>=30)注意看题目,边缘数是否包含在内也可能导致错误

        理解了十进制数的求法,n进制的情况就很好求解了,只需在每次执行(3)时先将m和它倒置后的数分别先转换成十进制相加,所得到的和再转回n进制即可

实现步骤

理解了要干什么之后,接下来就可以正式撸代码啦~

1.判断一个数是否为回文数

        因为回文数的特点是首位不为零,且从左向右读与从右向左读都一样,所以可以用for循环的方法判断第i位和第len-1-i位是否相等,也可以定义left和right变量,用while循环判断,每次判断之后left++,right--

下面分别给出两种方法的代码:

int hui(int len, char m[101]) {
    for (int i = 0; i < len; i++) {
        if (m[i] != m[len - 1 - i]) return 0;
    }
    return 1;
};
int hui(int len, char m[101]) {
    int left = 0, right = len - 1;
    while (left < right) {
        if (m[left] != m[right])  return 0;
        left++;
        right--;
    }
    return 1;
};

2.进制转换

n进制转成十进制

n进制转十进制时,从后往前每次取出数组的一位,将该数的权加到原来的sum上(权就是pow(n,len-1-i),不理解的可以去找n进制转十进制怎么算)

注意:

如果本来就是十进制,每次将数组每一位取出来与原来的sum的十倍相乘再赋给sum即可。

若十进制不特殊处理,当有一位为0时,就会出现tmp = 0* pow(n, len - 1 - i)=0的情况,使程序运行时出错。

long long int nToDec(int n, char m[101], int len) {
    long long int sum = 0;
    if (n == 10) {
        for (int i = 0; i < len; i++) {
            int r = m[i] - '0';
            sum = sum * 10 + r;
        }
    }
    else {
        for (int i = len - 1; i >= 0; i--) {
            int r = 0;
            if (n == 16 && m[i] >= 'A') {
                r = m[i] - 'A' + 10;
            }
            else {
                r = m[i] - '0';
            }
            int tmp = r * pow(n, len - 1 - i);
            sum += tmp;
        }
    }
    return sum;
}

十进制转成n进制

将十进制的每一位取出(用取模运算%)后转成对应n进制,while循环结束后得到的m数组是反的,所以还要每位交换一下才能得到正确的m

注意:

只有n == 16 && (sum % n) >= 10时,才用m[i] = (sum % n) + 'A' - 10  也就是说,只有A-F才这样处理,否则即使是16进制,也用 m[i] = (sum % n) + '0';

void decTon(int n, char m[], long long int sum) {
    int i = 0;
    while (sum) {

        if (n == 16 && (sum % n) >= 10) {
            m[i] = (sum % n) + 'A' - 10;
        }
        else {
            m[i] = (sum % n) + '0';
        }
        sum /= n;
        i++;
    }
    int l = 0, r = i - 1;
    while (l < r) {
        char tmp = m[l];
        m[l] = m[r];
        m[r] = tmp;
        l++;
        r--;
    }

}

3.转成十进制后相加

注意:

相加时sum要设成long long 类型,否则若step较大时,sum会超出int的范围导致结果出错

void addhui(int n, char m[], int len) {
    char mm[101] = { 0 };
    for (int i = 0; i < len; i++) {
        mm[len - 1 - i] = m[i];
    }
    long long int sum = nToDec(n, m, len) + nToDec(n, mm, len);
    decTon(n, m, sum);
}

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int hui(int len, char m[101]) {
    for (int i = 0; i < len; i++) {
        if (m[i] != m[len - 1 - i]) return 0;
    }
    return 1;
};
void decTon(int n, char m[], long long int sum) {
    int i = 0;
    while (sum) {

        if (n == 16 && (sum % n) >= 10) {
            m[i] = (sum % n) + 'A' - 10;
        }
        else {
            m[i] = (sum % n) + '0';
        }
        sum /= n;
        i++;
    }
    int l = 0, r = i - 1;
    while (l < r) {
        char tmp = m[l];
        m[l] = m[r];
        m[r] = tmp;
        l++;
        r--;
    }

}
//3602001953
long long int nToDec(int n, char m[101], int len) {
    long long int sum = 0;
    if (n == 10) {
        for (int i = 0; i < len; i++) {
            int r = m[i] - '0';
            sum = sum * 10 + r;
        }
    }
    else {
        for (int i = len - 1; i >= 0; i--) {
            int r = 0;
            if (n == 16 && m[i] >= 'A') {
                r = m[i] - 'A' + 10;
            }
            else {
                r = m[i] - '0';

            }


            int tmp = r * pow(n, len - 1 - i);
            sum += tmp;
        }
    }
    return sum;
}
void addhui(int n, char m[], int len) {
    char mm[101] = { 0 };

    for (int i = 0; i < len; i++) {
        mm[len - 1 - i] = m[i];
    }
    int lenmm = len;
    
    long long int sum = nToDec(n, m, len) + nToDec(n, mm, lenmm);
    
    decTon(n, m, sum);
    

}


int main() {
    int n, step = 0,len = 0;
    char m[101] = { 0 };
    scanf("%d %s", &n, m);
    len = strlen(m);
    while (len = strlen(m), hui(len, m) == 0) {
       
        step++;
       
        if (step >= 30) break;
        addhui(n, m, len);
        
    }
    if (step < 30) printf("STEP=%d", step);
    else printf("Impossible!");

    return 0;
}
  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值