当前位置: 代码迷 >> 综合 >> C语言牛客网刷题日记:BC158 [NOIP1999]回文数
  详细解决方案

C语言牛客网刷题日记:BC158 [NOIP1999]回文数

热度:71   发布时间:2023-12-06 13:56:59.0

题目链接:戳我戳我


目录

?

一.回文数

二:进制问题(此题的关键)

三:代码实现

1.数据的输入

2.由于字符'A'与'9'的阿斯克码的差值并不是1,所以要进行如下操作:

3.回文函数

4.头尾相加的操作:

四.完整代码



首先附上此代码的排名:


让我们来分析分析这道题目:

一.回文数

回文数是从左边往右边读和从右边往左边读是一模一样的数。

本题中还嵌入了进制的讨论,看起来很复杂,但是本蒟蒻都能做出来,你也可以!

下一条就是关于进制的讨论。

二:进制问题(此题的关键

进制可以简单的理解为数到了多少就要进1,比如我们最熟悉的10进制就是到了10就要进1,同理,二进制就是到了2就要进1,十六进制就是到了16就要进1(注意十六进制的10~15是用字母'A'~'F'来表示)。

三:代码实现

1.数据的输入


int n;
char m[2][101];//定义成全局变量默认为0

为什么用字符数组呢?

因为题目中说了有十六进制,所以输入的数据中会有字母,所以应该用字符数组来储存,

那为什么是一个两行的二维数组呢?

因为题中有要求进行操作:将数据的头尾相加,所以需要两个一位数组来进行操作。

2.由于字符'A'与'9'的阿斯克码的差值并不是1,所以要进行如下操作:


 int sz = strlen(m[0]);for (int i = 0; i < sz; i++)//转化成对应的数值{if (isdigit(m[0][i]))m[0][i] -= '0';if (isupper(m[0][i]))m[0][i] =m[0][i]-'A'+10;}

将字符都转变成其所表示的阿斯克码数值,这样进行操作的时候就方便很多。

这里有一个很重要的问题:如果是0怎么办?

看到了我设置的变量  sz  了吗,这就是用来记录当前串的长度的变量,由于题中进行的头尾相加操作只可能使得数字串的长度加一或者不变,所以只需要在数字串长度加一的时候  sz++  就可以完全正确的记录数字串的长度了。

3.回文函数

代码直接奉上:


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

此函数判断数字串是不是回文数的时候就返回0,是回文数的时候就返回1,这样便于后面的if语句的判断(1表示真,0表示假)。

4.头尾相加的操作:

代码奉上


 while (step++ < 30)//将操作次数控制为至多三十次,符合题意{int i = sz-1;int j = 0;int k=step%2;//这里是将k控制成1或者0,以此来实现两个一维数组的交替操作for (; i >= 0; i--, j++)//这里很重要******************************************{m[k][i] = m[1-k][j] + m[1-k][i];}for (i = 0; i < sz; i++)//判断进行进一位的操作{if (m[k][i] >= n){m[k][i] -= n;m[k][i + 1]++;if (i == sz - 1)sz++;//最后一位进1的话要把数字串的长度记录加1}}if (is_huiwen(m[step % 2], sz))//回文判断{printf("STEP=%d", step);return 0;//是回文就输出并且立即退出程序}}

除了我标记为很重要的那一部分其他你们应该都看懂了,这里就不过多阐述。

为什么我标记的地方那么重要:

因为我们要进行进制加1的操作,如果我们按照正序来存储数据的话,当数字串的位数加一的时候,我们就得把每个数据都往右都挪动一位(这也太麻烦了),所以我们倒着存储,当需要数字串位数加1的时候我们只需要在数字串的末尾加上1就行了,不用就行挪动(是不是很妙)。

下面是图解:


 


这样时间又更加充裕了起来(不会超时了) .

四.完整代码

#include<stdio.h>
#include<string.h>
#include<ctype.h>
int n;
char m[2][101];//定义成全局变量,默认为0
int is_huiwen(char m[101], int len)//判断回文函数
{int i = 0, j = len - 1;for (; i < j; i++, j--){if (m[i] != m[j])return 0;}return 1;
}
int main()
{scanf("%d ", &n);scanf("%s", m[0]);int sz = strlen(m[0]);//记录数字串长度int step = 0;for (int i = 0; i < sz; i++)//转化成对应的数值{if (isdigit(m[0][i]))//这里注意包含头文件<ctype.h>m[0][i] -= '0';if (isupper(m[0][i]))m[0][i] =m[0][i]-'A'+10;}if (is_huiwen(m[0], sz)){printf("STEP=%d", step);return 0;}while (step++ < 30)//控制30步{int i = sz-1;int j = 0;int k=step%2;//0和1交替for (; i >= 0; i--, j++)//头尾相加操作{m[k][i] = m[1-k][j] + m[1-k][i];}for (i = 0; i < sz; i++)//进制加1操作{if (m[k][i] >= n){m[k][i] -= n;m[k][i + 1]++;if (i == sz - 1)sz++;}}if (is_huiwen(m[step % 2], sz)){printf("STEP=%d", step);return 0;}}printf("Impossible!");
}


最后如果你觉得这篇文章对你有帮助的话,一定不要吝啬手中的收藏和赞,你们的支持就是我前进的动力(一个赞一道题)!!!!!!