[NOIP1999]回文数——(C语言)

一、题目

题目描述

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

例如:给定一个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

二、C语言完整代码

#include<stdio.h>
#include<string.h>
#include<ctype.h>
void add(char *s,char *s2,int n);
void opposide(char *s,char *s2);
int judge(char *s);
int main()
{
    int n;
    char s[110],s2[110];
    scanf("%d",&n);//输入 n 进制的数 s
    getchar();
    scanf("%s",s);
    int step=0;
    if(judge(s)) {printf("STEP=%d",step);return 0;}
    while(1)
    {
        step++;
        opposide(s,s2);
        add(s,s2,n);
        if(judge(s)){printf("STEP=%d",step);return 0;}
        if(step==30){printf("Impossible!"); return 0;}
    }
}
void opposide(char *s,char *s2)
{
    int n=strlen(s);
    int i;
    for(i=0;i<n;i++)
    s2[i]=s[n-i-1];
    s2[n]='\0';
}
int judge(char *s) //判断是否回文数,返回值 是1 否0
{
    int n=strlen(s);
    int i;
    for(i=0;i<n/2;i++)
    {
        if(s[i]!=s[n-i-1]) return 0;
    }
    return 1;
}
void add(char *s,char *s2,int x)
{
    int n=strlen(s);
    int c[110]={0};
    int i;
    for(i=0;i<n;i++)
    {
        if(isdigit(s[i])) c[n-i-1]+=s[i]-'0';
        else c[n-i-1]+=s[i]-'A'+10;
        if(isdigit(s2[i])) c[n-i-1]+=s2[i]-'0';
        else c[n-i-1]+=s2[i]-'A'+10;
    }  //此时c数组存储的为倒序
    for(i=105;i>=0;i--)
    {
        if(c[i]!=0) break;
    }
    n=i+1;
    i=0;
    while(1)
    {
        if(c[i]==0&&i>=n) break;
        if(c[i]>=x) 
        {
            c[i+1]+=c[i]/x;c[i]%=x;
        }
        i++;
    }
    n=i;
    for(i=0;i<n;i++)
    {
        if(c[n-i-1]>=0&&c[n-i-1]<=9) s[i]=c[n-i-1]+'0';
        else s[i]=c[n-i-1]+'A'-10;
    }
    s[n]='\0';
}

三、解析

1.程序可能输入不同进制的数,可能出现当进制大于10时可能出现字母,所以输入的数要作为字符串类型进行输入

    scanf("%d",&n);//输入 n 进制的数 s
    getchar();
    scanf("%s",s);

2.自定义函数judge 判断s字符串是否是回文数

int judge(char *s) //判断是否回文数,返回值 是1 否0
{
    int n=strlen(s);
    int i;
    for(i=0;i<n/2;i++)
    {
        if(s[i]!=s[n-i-1]) return 0;
    }
    return 1;
}

注意是字符串s而不是整数int类型的 

3.自定义opposide函数 将字符串s1倒序放入字符串s2

void opposide(char *s,char *s2)
{
    int n=strlen(s);
    int i;
    for(i=0;i<n;i++)
    s2[i]=s[n-i-1];
    s2[n]='\0';
}

4.自定义add函数,将正序字符串s和倒序字符串s2以n进制的数相加

void add(char *s,char *s2,int x)
{
    int n=strlen(s);
    int c[110]={0};
    int i;
    for(i=0;i<n;i++)
    {
        if(isdigit(s[i])) c[n-i-1]+=s[i]-'0';
        else c[n-i-1]+=s[i]-'A'+10;
        if(isdigit(s2[i])) c[n-i-1]+=s2[i]-'0';
        else c[n-i-1]+=s2[i]-'A'+10;
    }  //此时c数组存储的为倒序
    for(i=105;i>=0;i--)
    {
        if(c[i]!=0) break;
    }
    n=i+1;
    i=0;
    while(1)
    {
        if(c[i]==0&&i>=n) break;
        if(c[i]>=x) 
        {
            c[i+1]+=c[i]/x;c[i]%=x;
        }
        i++;
    }
    n=i;
    for(i=0;i<n;i++)
    {
        if(c[n-i-1]>=0&&c[n-i-1]<=9) s[i]=c[n-i-1]+'0';
        else s[i]=c[n-i-1]+'A'-10;
    }
    s[n]='\0';
}

这一段自定义函数比长,分开来看

4.1

将s和s2 字符串以数的类型相加存入c数组,c数组为int类型,所以可以存储大于等于10的数,我们在后面再次对c数组进行处理。

我们此时存入c数组按照倒序存入,方便后面的进位计算。

for(i=0;i<n;i++)
    {
        if(isdigit(s[i])) c[n-i-1]+=s[i]-'0';
        else c[n-i-1]+=s[i]-'A'+10;
        if(isdigit(s2[i])) c[n-i-1]+=s2[i]-'0';
        else c[n-i-1]+=s2[i]-'A'+10;
    } 

4.2

处理进位,按照进制进位。该位保留余数,整除数给下一位加上。

i=0;
while(1)
    {
        if(c[i]==0&&i>=n) break;
        if(c[i]>=x) 
        {
            c[i+1]+=c[i]/x;c[i]%=x;
        }
        i++;
    }

4.3

最后把c数组存入s字符串就可以了

n=i;
    for(i=0;i<n;i++)
    {
        if(c[n-i-1]>=0&&c[n-i-1]<=9) s[i]=c[n-i-1]+'0';
        else s[i]=c[n-i-1]+'A'-10;
    }
    s[n]='\0';

s是字符串数组,而c是整数型数组,进行转换即可。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值