回文数题解

说明

若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个10进制数56,将56加56(即把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,每组的第一行输入N,第二行输入M。

输出格式

对于每组输入数据,输出最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出"Impossible!"。

样例

9
87
STEP=6

 c语言版:

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

#define MAX 5000 // 定义字符数组的最大长度

int len, d, lim = 30; // len表示字符串长度,d表示进制,lim表示最多进行30次操作
char str[MAX], rts[MAX]; // str用于存储原始字符串,rts用于存储反转后的字符串

// 将字符串b反转,并存入字符串a中
void fz(char a[MAX], char b[MAX]) {
    // 从b的末尾依次赋值到a的前面,实现反转
    for (int i = 0; i < len; ++i) {
        a[i] = b[len - 1 - i];
    }
    a[len] = '\0'; // 确保字符串末尾是'\0'结束符
}

// 实现字符串str和rts的按进制d的加法,并存入rts
void add() {
    int carry = 0; // carry用于存储进位
    for (int i = 0; i < len; ++i) {
        // 将str和rts对应位相加,并加上进位carry
        rts[i] += str[i] - '0' + carry;
        carry = (rts[i] - '0') / d; // 计算进位值
        rts[i] = (rts[i] - '0') % d + '0'; // 当前位取模,重新变成字符
    }
    // 如果有进位,处理进位部分
    if (carry) {
        rts[len] = '0' + carry;
        rts[++len] = '\0'; // 增加新的一位,并确保字符串以'\0'结尾
    }
}

// 判断当前字符串rts是否为回文
int judge() {
    // 从两端向中间逐位比较字符
    for (int i = 0; i < len; ++i) {
        if (rts[i] != rts[len - 1 - i]) {
            return 0; // 如果存在不相等的字符,返回0表示不是回文
        }
    }
    return 1; // 如果所有字符都相等,返回1表示是回文
}

int main() {
    // 输入进制d和字符串str
    scanf("%d %s", &d, str);

    // 将输入字符串中的大写字母转换为相应的数字
    for (int i = 0; i < strlen(str); ++i) {
        if ('A' <= str[i] && str[i] <= 'Z') {
            str[i] = str[i] - 'A' + '9' + 1; // 将'A'-'Z' 转换为 10-35
        }
    }

    // 最多进行lim(30次)的操作,寻找回文数
    for (int i = 0; i <= lim; ++i) {
        len = strlen(str); // 获取当前字符串长度
        fz(rts, str); // 将str反转存入rts中

        // 判断rts是否为回文,如果是则退出循环
        if (judge()) {
            printf("STEP=%d\n", i); // 输出找到回文的步骤数
            return 0;
        }

        // 如果不是回文,则将str和rts相加,并存入rts中
        add();
        fz(str, rts); // 将rts反转后重新存入str,进行下一次循环
    }

    // 如果超过30次仍然没有找到回文,则输出"Impossible!"
    printf("Impossible!\n");
    return 0;
}

解释:

  1. 主函数

    • 输入进制 d 和字符串 str
    • 将输入字符串中的大写字母转换为对应的数字(A 转换为 10,B 转换为 11,依次类推)。
    • 循环最多进行 lim 次操作,每次检查是否为回文,如果是回文则输出操作步数 STEP=n,如果超过 lim 次仍未找到回文则输出 Impossible!
C 语言版本的关键点:
  • C 语言中数组操作需要手动管理字符数组的末尾 \0,这是与 C++ 中 string 的区别之一。
  • 输入与输出使用 scanfprintf,比 C++ 更为低级,但更加高效

C++ 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vll;
typedef pair<int,int> pii;
#define endl '\n'
const ll MAXN = 2e5+10; // 定义最大数组长度
char letter[20] = "0123456789ABCDEF"; // 进制表示用到的字符表

// 将字符转换为数字的函数
int char_to_int(char c) {
    // 如果是数字字符(0-9),则返回数字本身;如果是字母(A-F),则返回对应的数值
    return isdigit(c) ? c - '0' : c - 'A' + 10;
}

// 将数字转换为字符的函数
char int_to_char(int n) {
    // 返回数字对应的进制字符
    return letter[n];
}

// 反转字符串并进行两数相加的函数,返回相加后的字符串
string radd(string a, int k) {
    string b = a; 
    reverse(b.begin(), b.end()); // 将字符串 a 反转,存储到 b 中
    string ans; // 用于存储最终的结果字符串
    vector<int> nums(a.length() + 1, 0); // 动态分配数组用于存储每一位的加和结果,并初始化为 0
    int aL = a.length(); // 获取字符串 a 的长度
    
    // 将字符转换为数字并进行对应位置的加法
    for (int i = 0; i < aL; i++) {
        int numa = char_to_int(a[i]); // 将 a[i] 转换为相应的数值
        int numb = char_to_int(b[i]); // 将 b[i] 转换为相应的数值
        nums[i] += numa + numb; // 对应位的两个数字相加
    }

    // 处理进位
    for (int i = 0; i < aL; i++) {
        if (nums[i] >= k) { // 如果当前位大于等于进制 k,则需要进位
            nums[i+1] += nums[i] / k; // 进位给下一位
            nums[i] %= k; // 当前位保留进制范围内的值
        }
    }

    if (nums[aL]) aL++;  // 如果最后有进位,则需要增加长度
    
    // 将结果转换回字符串
    for (int i = aL - 1; i >= 0; i--) {
        ans += int_to_char(nums[i]); // 将数字转换为字符并拼接到结果字符串中
    }
    return ans; // 返回相加后的字符串
}

int main() {
    ios_base::sync_with_stdio(false); // 提高输入输出效率,关闭 C 风格的同步
    cin.tie(nullptr); // 取消 cin 和 cout 的绑定,进一步提升性能

    string M; // 用于存储输入的数字字符串
    int N, cnt = 1; // N 表示输入的进制,cnt 表示步骤计数,初始化为 1
    cin >> N >> M; // 输入进制 N 和数字字符串 M
    
    string temp = radd(M, N), s; // 调用 radd 函数将 M 和它的反转相加,存储到 temp 中
    s = temp; 
    reverse(s.begin(), s.end()); // 将 temp 反转,存储到 s 中

    // 循环直到找到回文数或者超过 30 步
    while (temp != s) { // 当 temp 不是回文时
        cnt++; // 步骤计数器加 1
        if (cnt > 30) { // 如果步骤超过 30,则输出 "Impossible!"
            cout << "Impossible!" << endl;
            return 0; // 程序结束
        }
        temp = radd(temp, N); // 将当前字符串 temp 与它的反转相加
        s = temp; 
        reverse(s.begin(), s.end()); // 将新的 temp 再次反转
    }

    // 如果找到回文数,输出步骤数
    cout << "STEP=" << cnt << endl;
    return 0; // 程序结束
}
#include<iostream>
#include<string.h>
using namespace std;

const int Max = 5000; // 最大字符数组大小
int len, d, lim = 30; // len表示字符串长度,d表示进制,lim表示最多进行30次操作
char str[Max], rts[Max]; // str是原始字符串,rts是反转后的字符串

// 将字符串b反转并存入字符串a中
void fz(char a[Max], char b[Max]) {
    // 遍历字符串b,将b的字符从末尾依次复制到a的前面,达到反转的效果
    for (int i = 0; i < len; ++i)
        a[i] = b[len - 1 - i];
}

// 实现str和rts的加法,并存回rts中,按指定进制d进行进位
void add() {
    int c = 0; // 用于保存进位
    // 从低位开始将str和rts对应位置的数字相加
    for (int i = 0; i < len; ++i) {
        rts[i] += str[i] - '0' + c; // 当前位的相加结果存入rts[i]
        c = (rts[i] - '0') / d; // 计算进位,当前位的值除以进制d
        rts[i] = (rts[i] - '0') % d + '0'; // 当前位的值取模进制d,并转回字符
    }
    // 如果最高位仍然有进位,则将进位存入rts的下一位
    if (c) rts[len] = '0' + c;
}

// 判断当前字符串rts是否为回文
bool judge() {
    // 从两端开始向中间逐位比较,如果有不相等的字符则返回false
    for (int i = 0; i < len; ++i)
        if (rts[i] != rts[len - 1 - i]) return false;
    // 如果所有字符都相等,则返回true,表示是回文
    return true;
}

int main() {
    // 输入进制d和字符串str
    cin >> d >> str;
    
    // 将输入字符串中的大写字母转换为对应的数字
    // 比如'A' 转换为 10,'B' 转换为 11,依次类推
    int i;
    for (i = 0; i < strlen(str); ++i) {
        if ('A' <= str[i] && str[i] <= 'Z') 
            str[i] = str[i] - 'A' + '9' + 1; // 大写字母转换为数字字符
    }

    // 最多进行lim(即30)次的加法反转判断操作
    for (i = 0; i <= lim; ++i) {
        len = strlen(str); // 计算当前字符串长度
        fz(rts, str); // 将str反转并存入rts
        
        // 判断rts是否为回文字符串,如果是则退出循环
        if (judge() == true) break;
        
        add(); // 如果不是回文,则将str和rts相加,并将结果存入rts中
        len = strlen(rts); // 更新rts的长度
        
        // 将rts再反转存入str,继续下一轮循环
        fz(str, rts);
    }
    
    // 输出结果,如果在30步以内找到回文,则输出步骤数
    if (i <= lim) cout << "STEP=" << i << endl;
    // 如果超过30步仍未找到回文,则输出"Impossible!"
    else cout << "Impossible!" << endl;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ws_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值