P2010 [NOIP2016 普及组] 回文日期 做题笔记

一、关于题目解读

  首先,这个题目核心要求是:判断用户给出的两个日期间为回文日期的数量是多少?我们先看如何储存这两个日期。可以用字符数组,整形变量来储存。那么,要用哪种呢?这就要看题目,首先对于一个日期是否回文,似乎可以用字符数组逐一比较,但我们明显不是要判断一个日期是否回文,这就要对日期进行变更,明显日期的变更用数学计算更加方便,在我思考许久后,还是采用整形变量储存(当然对于字符数组的日期变更还有更好的算法,只是现在小白的我还不知道)

以下为日期的输入代码

int num1;
int num2;
scanf("%d", &num1);
scanf("%d", &num2);

二、解题思路

  首先,对输入的两个日期,我们要进行拆分工作,即把年月日都提取出来,对于年,将得到的日期除以10000就可以得到,同理,对于月和日也是同样的操作。当然对于月和日我整合在一起了。

int year=num/10000;
int month=num%10000;

  接下来,就要考虑回文的判断,其实我们可以很容易发现,对于回文,只要年的反转的数为后面月和日的数,那它就是回文日期。例如,20011002,2001年的反转为1002,即十月二号。所以为了判断回文,就需要一个反转函数。如下

//将一串数字反转的函数
int fan(int x)
{
	int a = 0;
	while (x != 0)
	{
		int b = x % 10;
		x /= 10;
		a = a * 10 + b;
	}
	return a;
}

  这就表明每一年只有一个回文日期,但不一定存在,因为,月份只有12个月,如3333年,所反转的日期是不存在的,这也是下面的一个判断条件。

   同时,题目的样例也给了我们出发点,即判断一年与多年的回文日期。先从判断一年的方向写。这里我们就不需要考虑年份,而一年只有一个回文日期(如果存在),即只要判断月与日的位置,即将年份反转后得到的日期与用户所给的日期范围进行判断就可以了。但我们还有其他条件,如闰年中的2月份,还有每个月的30,31号问题,现假设一个有效日期函数youxiao,用它来判断日期是否有效。这样主函数的核心就写出来了。

int num1;
int num2;
scanf("%d", &num1);
scanf("%d", &num2);
int year1 = num1 / 10000;
int year2 = num2 / 10000;
int month1 = num1 % 10000;
int month2 = num2 % 10000;
//年份不变
if (year1 == year2)
{
	int month3 = fan(year1);
	if (month3 >= month1 && month3 <= month2)
	{

		if (youxiao(month3, year1))
		{
			printf("1");
		}
		else
		{
			printf("0");
		}
	}
	else
	{
		printf("0");
	}
}

   因此问题的关键就是这个youxia函数。首先要判断的就是一个闰年问题。简单,上代码。

//判断是否为闰年的函数
int run(int x)
{
	if (x % 4 == 0 && x % 100 != 0)
	{
		return 1;
	}
	else if (x % 400 == 0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

   再说回有效日期函数,由于2月份是特例就先判断二月份,在判断其他月份。直接上代码。

//判断日期的有效性的函数
int youxiao(int x,int year)
{
	int month = x / 100;
	int day = x % 100;
	if (month == 2 )
	{
		if (run(year))
		{
			if (day <= 29)
			{
				return 1;
			}
			else
			{
				return 0;
			}
		}
		else 
		{
			if (day <= 28)
			{
				return 1;
			}
			else
			{
				return 0;
			}

		}
	}
	else
	{
		if (month <= 7)
		{
			if (month % 2 == 0)
			{
				if (day <= 30)
					return 1;
				else
					return 0;
			}
			else
			{
				if (day <= 31)
					return 1;
				else
					return 0;
			}
		}
		else if (month <= 12)
		{
			if (month % 2 == 0)
			{
				if (day <= 31)
					return 1;
				else
					return 0;
			}
			else
			{
				if (day <= 30)
					return 1;
				else
					return 0;
			}
		}
		else
			return 0;
	}
}

  对于30与31号的判断,7和8月是关键节点,同时注意月份不能超过12月。而这个题的核心代码就写出来了,对于两个不一样的年份也是同样的思路,这里用for循环遍历年份,同时注意一年日期的范围在101与1231之间,即一月一号与十二月三十一号,这里对第一年与最后一年进行了讨论。如下。

int sum = 0;
for (int i = year1; i <= year2; i++)
{
	int month3 = fan(i);
	if (i == year1)
	{
		if (month3 >= month1&&month3<=1231)
		{
			if (youxiao(month3, i))
			{
				sum++;
			}
		}
	}
	else if (i == year2)
	{
		if (month3 <= month2&&month3>=101)
		{
			if (youxiao(month3, i))
			{
				sum++;
			}
		}
	}
	else
	{
		if (month3 >= 101 && month3 <= 1231)
		{
			if (youxiao(month3, i))
			{
				sum++;
			}
		}
	}
}
printf("%d", sum);

三、最终AC代码

#include<stdio.h>
//判断是否为闰年的函数
int run(int x)
{
	if (x % 4 == 0 && x % 100 != 0)
	{
		return 1;
	}
	else if (x % 400 == 0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
//判断日期的有效性的函数
int youxiao(int x,int year)
{
	int month = x / 100;
	int day = x % 100;
	if (month == 2 )
	{
		if (run(year))
		{
			if (day <= 29)
			{
				return 1;
			}
			else
			{
				return 0;
			}
		}
		else 
		{
			if (day <= 28)
			{
				return 1;
			}
			else
			{
				return 0;
			}

		}
	}
	else
	{
		if (month <= 7)
		{
			if (month % 2 == 0)
			{
				if (day <= 30)
					return 1;
				else
					return 0;
			}
			else
			{
				if (day <= 31)
					return 1;
				else
					return 0;
			}
		}
		else if (month <= 12)
		{
			if (month % 2 == 0)
			{
				if (day <= 31)
					return 1;
				else
					return 0;
			}
			else
			{
				if (day <= 30)
					return 1;
				else
					return 0;
			}
		}
		else
			return 0;
	}
}
//将一串数字反转的函数
int fan(int x)
{
	int a = 0;
	while (x != 0)
	{
		int b = x % 10;
		x /= 10;
		a = a * 10 + b;
	}
	return a;
}
int main()
{
	int num1;
	int num2;
	scanf("%d", &num1);
	scanf("%d", &num2);
	int year1 = num1 / 10000;
	int year2 = num2 / 10000;
    int month1 = num1 % 10000;
    int month2 = num2 % 10000;
	//年份不变
	if (year1 == year2)
	{
		int month3 = fan(year1);
		if (month3 >= month1 && month3 <= month2)
		{

			if (youxiao(month3, year1))
			{
				printf("1");
			}
			else
			{
				printf("0");
			}
		}
		else
		{
			printf("0");
		}
	}
	else
	{
		int sum = 0;
		for (int i = year1; i <= year2; i++)
		{
			int month3 = fan(i);
			if (i == year1)
			{
				if (month3 >= month1&&month3<=1231)
				{
					if (youxiao(month3, i))
					{
						sum++;
					}
				}
			}
			else if (i == year2)
			{
				if (month3 <= month2&&month3>=101)
				{
					if (youxiao(month3, i))
					{
						sum++;
					}
				}
			}
			else
			{
				if (month3 >= 101 && month3 <= 1231)
				{
					if (youxiao(month3, i))
					{
						sum++;
					}
				}
			}
		}
		printf("%d", sum);
	}
	return 0;
}

最后提一句,这是在字符串专题里找的题目,所以一定有字符串的解法。

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cyemd

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

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

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

打赏作者

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

抵扣说明:

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

余额充值