文章目录
前言
今天我们来看一道我个人认为很有意思的题,乍一看好像很简单,却有很多细微之处容易忽略。下面把我当时解题的思路展现出来,其实算法并不难,只是当初第一次做的时候花了我很多时间去对每一种情况进行讨论,现在看来依然望而生畏。大佬们有任何好的解法欢迎留言到评论区![doge][doge][doge]
原题复现
简要分析
首先,要求小明的出生日期和现在的日期之间相差的天数,我们很容易就想到闰年和平年的问题。其次,我们还要分析输入的两个年份是同一年还是不同年,这两种情况也是不一样的。而题目的难点就在判断使是否是闰年后天数的计算上。我们易得到以下几个问题:
1、出生年是否是闰年;
2、今年是否是闰年;
3、出生年与今年之间是否相差闰年,相差几个闰年。
其次,如果是两者是同一年,我们还要考虑是否是同一月的情况。
实现过程
假设输入的起始年、月、日分别为y1、m1、d1,输入的终止年、月、日分别为y2、m2、d2。即以y1-m1-d1 y2-m2-d2的形式输入,并设总天数为D。(即要求的天数为D)
1.判断闰年函数
由于程序中有多处涉及到闰年的判断,我们先单独封装一个用来判断是否是闰年的函数。是闰年返回1,不是闰年返回0。
int prime(int n)
{
if ((n % 4 == 0) && (n % 100 != 0) || (n % 400 == 0))
{
return 1;//是闰年
}
else
{
return 0;//不是闰年
}
}
1.设置两个数组存放闰年和平年的每月天数
这里我们设置两个大小为13的数组,是为了方便我们后面直接将月份作为数组下标来获得数组元素,每个月份正好与数组下标相对应,这种方法非常常见。
int days1[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31 };//平年每月天数
int days2[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31 };//闰年每月天数
3.求y1与y2之间相差的天数
我们先不管y1、y2这两个年份的天数,先求出y1、y2之间相差的年数并判断闰年,如果是闰年,直接D+366;如果是平年,直接D+365。
for (i = y1 + 1; i < y2; i++)//先不管y1、y2这两个年份,只看两者中间的年份
{
if (prime(i) == 1)//是闰年
{
D += 366;
}
else//是平年
{
D += 365;
}
}
4.起始年与终止年是同一年
如果起始年与终止年是同一年
①是同一月
先判断是同一年同一月的情况,则直接用终止日期减去起始日期得到相差天数。
if (y1 == y2)//输入的是同一年
{
if (m1 == m2)
{
D += (d2 - d1);
}
②是不同月
a.如果两者都是闰年
if (prime(y1) == 1)//两者都是闰年
{
D += days2[m1] - d1;//先算出起始月当月剩余天数
for(i = m1 + 1; i < m2; i++)
{
D += days2[i];//再计算起始月与终止月之间相差的天数
}
D += d2;//最后加上终止月当月天数
}
b.如果两者都是平年
else//两者都是平年
{
D += days1[m1] - d1;//先算出起始月当月剩余天数
for (i = m1 + 1; i < m2; i++)
{
D += days1[i];//再计算起始月与终止月之间相差的天数
}
D += d2;//最后加上终止月当月天数
}
5.起始年与终止年是不同年
如果起始年与终止年是不同年,其实计算思路都是一样的,只是由于平年和闰年的区别需要代入不同的数组进行运算。
①y1是闰年
if (prime(y1) == 1)//y1是闰年
{
D += days2[m1] - d1;//先算出起始月当月剩余天数
for (i = m1 + 1; i < 13; i++)//起始月的下一月~12月
{
D += days2[i];//再计算起始年当年剩余天数
}
}
②y1是平年
else//y1是平年
{
D += days1[m1] - d1;//先算出起始月当月剩余天数
for (i = m1 + 1; i < 13; i++)//起始月的下一月~12月
{
D += days1[i];//再计算起始年当年剩余天数
}
}
③y2是闰年
if (prime(y2) == 1)//y2是闰年
{
D += d2;//先算出终止月当月已过的天数
for (i = 1; i < m2; i++)//终止年的1月~终止月的上一月
{
D += days2[i];//再计算终止年当年已过的天数
}
}
④y2是平年
else//y2是平年
{
D += d2;//先算出终止月当月已过的天数
for (i = 1; i < m2; i++)//终止年的1月~终止月的上一月
{
D += days1[i];//再计算终止年当年已过的天数
}
}
完整源码
#include <stdio.h>
int prime(int n)
{
if ((n % 4 == 0) && (n % 100 != 0) || (n % 400 == 0))
{
return 1;//是闰年
}
else
{
return 0;//不是闰年
}
}
int main()
{
int y1 = 0, m1 = 0, d1 = 0, y2 = 0, m2 = 0, d2 = 0;
scanf("%d-%d-%d %d-%d-%d", &y1, &m1, &d1, &y2, &m2, &d2);
int days1[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31 };//平年每月天数
int days2[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31 };//闰年每月天数
int i = 0, D = 0;
for (i = y1 + 1; i < y2; i++)
{
if (prime(i) == 1)//是闰年
{
D += 366;
}
else//是平年
{
D += 365;
}
}
if (y1 == y2)//输入的是同一年
{
if (m1 == m2)
{
D += (d2 - d1);
}
else
{
if (prime(y1) == 1)//两者都是闰年
{
D += days2[m1] - d1;
for(i = m1 + 1; i < m2; i++)
{
D += days2[i];
}
D += d2;
}
else//两者都是平年
{
D += days1[m1] - d1;
for (i = m1 + 1; i < m2; i++)
{
D += days1[i];
}
D += d2;
}
}
}
else//不同年
{
if (prime(y1) == 1)//y1是闰年
{
D += days2[m1] - d1;
for (i = m1 + 1; i < 13; i++)
{
D += days2[i];
}
}
else//y1是平年
{
D += days1[m1] - d1;
for (i = m1 + 1; i < 13; i++)
{
D += days1[i];
}
}
if (prime(y2) == 1)//y2是闰年
{
D += d2;
for (i = 1; i < m2; i++)
{
D += days2[i];
}
}
else//y2是平年
{
D += d2;
for (i = 1; i < m2; i++)
{
D += days1[i];
}
}
}
printf("%d\n", D);
return 0;
}
总结
写完这篇博客后,我发现这道题不是难,是麻烦!其实计算思路非常简单,就是要有耐心去对每一种情况进行分析并计算,也有很多细节需要注意。
这也告诉我们,想做程序员一定要耐得住寂寞,一定要有耐心!
Patience!Patience!And patience!