用户输入: 年 月 日 及天数 程序运行后打印出具体的日期 例如:输入 1989 11 20 20 输出 1989 12 10
大一小白第一次写博文感觉这个对自己有点绕,写下来理下思路,还请各位路过的大佬多多指点。
主要思路:
(用老师的一句话,这应该是 “大力出奇迹” 的算法)
一、解题思路来源于另一个题:
给出一个年份以及天数,输出对应的年、月、日
这个题目
首先先理解上面这个题目:
1.初始日期:输入的年份–1月–1日
从这里分析年份就有两种情况 闰年和非闰年
因而,可以通过建立一个二维数组,把每个月的天数情况直接表示出来,第一个元素放零是为了方便后面直接用下标代表月份
monthdays[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31} }; //定义数组存放费闰年和闰年每个月天数
2.闰年的判别:
leap = (year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0; //判断是否为闰年
不用if语句是因为可以直接用leap的真值代表数组的行标
3.天数与月份的确定:
通过用所需加的天数,对每个月天数逐次作差,直到
天数的值 <= 该轮循环的月数的天数
就求出当月的天数以及月份
for (k = 1; days >= monthdays[leap][k] ; k++)
days -= monthdays[leap][k];
//不满足循环条件时的 days 就是 日的值,k 就是 月的值
———————————分割线—————————————
二、现在开始回归正题:
这道题的区别在于初始日期不固定,因而会带来两个主要问题:
(1)跨年月份变换问题
如:12月—>1月
(2)跨年后是否闰年问题
如:2000年(闰年)—>2001(非闰年)
由此我的解题思路主要就是围绕解决这两个问题。
1.首先开始解决天数为正数的时候
先把代码单独列出来吧
//days 要加的天数 ,year,month,day输入的年月日
void howday1(int days, int year, int month, int day)
{
int monthdays[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31} }; //定义数组存放费闰年和闰年每个月天数
int leap, k;
int i = 0; //用于判段初始月
days += day; //将起始月的天数归零
do //外层循环计算年
{
leap = (year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0; //判断是否为闰年
for (k = 1; days >= monthdays[leap][k] ; k++) //计算月和当月日期
{
if (i == 0 && k == 1) //由初始月份开始
k = month;
i++; //i增加后面就不可能出现初始月
days -= monthdays[leap][k]; //用总天数减去对应月的天数
if (k == 12)
{
k = 1;
year++;
break; //k=12时离开内循环年数加1,回到1月
}
}
}while( days >= monthdays[leap][k] );
printf("%d %d %d", year, k, days);
}
与开始描述的那道题目类似,这个题主要症结在于没有确定的起始日期,由此我首先想到的是将给的起始日期全部清零变成当年的1月1日,但想了一下这样做有点麻烦运算量会更大,所以选择让当月的天数归零变成1日,保留月份以及年份;(我感觉可能就是我这个想法导致了我觉得我写的代码太绕了)
所以有了这个操作
days += day; //将起始月的天数归零
然后和先前一样直接用总天数 减 接下来每个月的天数
但这个时候跨年问题就出现了当算到12月时年份就需要加一,并且还要考虑接下来的一年是否为闰年,所以我想到了两层循环外层当用来对年递增,并判断是不是闰年,内层就对月还有天数进行计算,当计算至12月时,days还不满足循环结束条件时就
跳出内层循环—>年数+1—>判断闰年—>从1月开始再进入内层循环
2.负数(和正数相似)
区别点:起始月需要-1从上一个月开始计算
总的思路就是如此
代码也试了很多数据暂时没找出bug
有的话请多多指教
**
下面是完整代码
**
#include<stdio.h>
void howday1(int days, int year, int month, int day);//正数
void howday2(int days, int year, int month, int day);//负数
int main()
{
int year,month,day; //输入的年月日
int days; //将要加的天数
scanf("%d %d %d", &year, &month, &day);
getchar(); //吃回车
scanf("%d", &days);
if (days == 0)
printf("%d %d %d", year, month, day);
else if(days > 0)
howday1(days, year, month, day);
else //调用函数计算加了天数后的日期
howday2(days, year, month, day);
}
void howday1(int days, int year, int month, int day)
{
int monthdays[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31} }; //定义数组存放费闰年和闰年每个月天数
int leap, k;
int i = 0; //用于判段初始月
days += day; //将起始月的天数归零
do //外层循环计算年
{
leap = (year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0; //判断是否为闰年
for (k = 1; days >= monthdays[leap][k] ; k++) //计算月和当月日期
{
if (i == 0 && k == 1) //由初始月份开始
k = month;
i++; //i增加后面就不可能出现初始月
days -= monthdays[leap][k]; //用总天数减去对应月的天数
if (k == 12)
{
k = 1;
year++;
break; //k=12时离开内循环年数加1,回到1月
}
}
}while( days >= monthdays[leap][k] );
printf("%d %d %d", year, k, days);
}
void howday2(int days, int year, int month, int day)
{
int monthdays[2][13]={{31,31,28,31,30,31,30,31,31,30,31,30,31},
{31,31,29,31,30,31,30,31,31,30,31,30,31} }; //定义数组存放费闰年和闰年每个月天数
int leap, k;
int i = 0;
days += day; //将起始月的天数归零
do //外层循环计算年
{
leap = (year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0; //判断是否为闰年
for (k = 12; days <= 0 ; k--)
{
if (i == 0 && k == 12) //由初始月份开始
k = month;
i++;
days += monthdays[leap][k-1]; //用总天数加上上一个月的天数
if (k == 1)
{
k = 12;
year--;
break; //k=1时离开内循环年数减1,回到12月
}
}
}while( days <= 0);
printf("%d %d %d", year, k, days);
}
总的来说就是感觉很不对,太绕了,希望有大佬指点一下,推荐一下更优化的代码。