题目描述:
输出自公元纪年以来的完全对称日
讲题过程:
关键字:
一、日期
二、回文
1、生成日期,判断是否回文
2、生成一个回文,判断他是不是一个日期
1、生成日期,判断是否回文:
如何判断回文?
正着for和倒着for一样的
比如:
abcdefgh
for(i=1;i<=8;++i)
if(s[i]!=s[8-i+1]) 不是回文
优化:判断一半的长度
for(i=1;i<=4;++i)
if(s[i]!=s[8-i+1]) 不是回文
如何生成日期?
由8位数字组成
1、8个for循环,对生成的每一个8位数,判断他是不是1个日期
边界问题:年份到每一位的上限之后,对后面的数字有约束
月份:第5/6位是不是01——12
日:1、闰年的2月29天 2、 1月、3月……31天 3、30天
年、月对日都有约束
麻烦,不用
改进:
生成年份:for 1——2020
生成月份 for 1——12
生成日: for 1——28/29.30.31
8位数放到数组里
2、生成一个回文,判断他是不是一个日期
如何判断是不是一个日期?
年、月、日?
分别提取出来
判断
年<=2020
月:月<=12
日:分三类
<=31
<=28 29
<=30
如何生成回文?
最开始想到生成1个四位数年份,镜像翻转
但忽略了日期并不一定是8位数
这样会漏下一些,比如10101,公元1年1月1日
生成年份1,镜像翻转得00011000
所以要对回文的长度进行讨论
如果回文是7位数,那么需要生成3位年份以及月份的第1位,镜像翻转前2位年份
如果回文是6位数,那么需要生成2位年份以及月份,镜像翻转2位年份和第1位月份
如果回文是5位数,那么需要生成1位年份以及月份,镜像翻转1位年份和2位月份
所以本思路就比较麻烦了
改进:不需要考虑闰月
若是8位:
XXXXPP29
92OOOOOO,年份超限
若是7位:
XXX0229
9220229,922年不是闰年
若是6位:
XX0229
9220XX,无法回文
若是5位:
X0229,无法回文
BUG:
边界问题,由于2020年只过了2个月加2天,所以存在边界问题,算到2019年,再额外加上1个即可(20200202)
梳理一下最终思路:
最终选择思路一:生成日期,判断是否回文
1、for 1——2019 生成年份
2、for 1——12 生成月份
3、for 1——30/31 生成日
4、放到一个数组里
5、判断是否回文,若回文,累加器+1
6、输出累加结果+1
代码:
'''
#include<stdio.h>
int len,s[9]; //数组保存日期,len记录长度
int judge(int m) //判断月份天数
{
if(m==2) return 28;
if(m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12) return 31;
return 30;
}
void turn(int y,int m,int d) //将生成的日期放到数组里
{
//由于年份长度不确定,所以采用将他们倒着放进去,即20190812存为21809102
//正序倒序不影响回文的判定
len=0;
if(d>=10) //日如果是个位数,要补1个0
while(d) s[++len]=d%10,d/=10;
else s[++len]=d,s[++len]=0;
if(m>=10) //月同上
while(m) s[++len]=m%10,m/=10;
else s[++len]=m,s[++len]=0;
while(y) s[++len]=y%10,y/=10;
}
int ok() //判断是否回文
{
int i,m=len/2;
for(i=1;i<=m;++i)
if(s[i]!=s[len-i+1]) return 0;
return 1;
}
int main()
{
int y,m,d,t,k,ans=0;
for(y=1;y<=2019;++y) //年 ,最后加上20200202,所以上界是2019
for(m=1;m<=12;++m) //月
{
t=judge(m); //得到月的天数上界
for(d=1;d<=t;++d) //日
{
turn(y,m,d); //放到数组里
if(ok()) //如果回文
{
ans++;
for(k=1;k<=len;++k) printf("%d",s[k]); //输出这个世界完全数
printf("\n");
}
}
}
printf("20200202\n");
printf("%d",ans+1);
}
'''