合法日期问题
一、 课题概述
知道日期的来历吗。我们通常以公元纪年,如公元2009年。
这种国际通行的纪年体系以传说中耶稣基督的生年为公历元年(相当于中国西汉平帝元年)。一年包括12个月,每个月的天数不全相同。
星期的起源应该是连系著月亮的周期,因为七天大约是月亮一周的四份之一。
Sunday、Monday、Tuesday、Wednesday、Thursday、Friday、Saturday依次表示星期日、星期一、星期二、星期三、星期四、星期五、星期六。
给定一个日期,判断是否合法。。
输入
对于每个测试用例:
输出YES或NO,判断y、m、d、w是否构成一个合法的日期。
二、 设计与实现
此题目对日期的合理性和所读入的星期进行判断,并进行相应的输出。
对日期规则设定利用if语句将所有不合法的范围列出并返回false。
计算星期几则利用基姆拉尔森计算公式W=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7
公式中d表示日期中的日数,m表示月份数,y表示年数。得到的值加1则是对应的星期。注意:在公式中有个与其他公式不同的地方:把一月和二月看成是上一年的十三月和十四月例:如果是2014-1-1则换算成:2013-13-1来代入公式计算,得W=2,W++,则对应周三。
定义bool back函数返回日期是否合法,若合法返回true,否则返回false。
Main函数得到返回值并进行相应的输出。
C++代码耗时约200Ms,但是C语言写的代码耗时约15Ms,于是代码都附上
以下分别为用C++和C语言实现具体代码:
C++:
#include<iostream>
using namespace std;
#include<string>
bool back(inty,int m,int d,charweek[])//boolback函数判断是否满足合法日期条件
{
if (m > 12 ||m <= 0 || y <= 0 ||d <= 0) return false;//此行及以下几行,当读入的y,m,d不符合日期的规则时return false
if (m == 12 &&d> 31) return false;
if (m == 11 &&d> 30) return false;
if (m == 10 &&d> 31) return false;
if (m == 9 &&d> 30) return false;
if (m == 8 &&d> 31) return false;
if (m == 7 &&d> 31) return false;
if (m == 6 &&d> 30) return false;
if (m == 5 &&d> 31) return false;
if (m == 4 &&d> 30) return false;
if (m == 3 &&d> 31) return false;
if (y % 4 != 0 || (y % 100 == 0 &&y %400 != 0))//此行判断是否闰年,以便对2月天数的限制
{
if (m ==2 &&d > 28) return false;
}
else
{
if (m ==2 &&d > 29) return false;
}
if (m == 1 &&d> 31) return false;
if (m == 1 ||m == 2)//判断星期用基姆拉尔森计算公式W=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7,得到的值加一则是对应的星期
{
m +=12;//基姆拉尔森计算公式把一月和二月须看成是上一年的十三月和十四月
y--;
}
switch (((d + 2 *m + 3 * (m + 1) / 5 +y + y / 4 - y / 100 + y / 400) % 7) + 1)
{
case 6:
if(strcmp(week,"Saturday") == 0)break;
return false;
//字符串的比较函数一般形式:strcmp(字符串1,字符串2)
//当s1<s2时,返回为负数
//当s1= s2时,返回值 = 0
//当s1>s2时,返回正数
case 5:
if(strcmp(week,"Friday") == 0)break;
return false;
case 4:
if(strcmp(week,"Thursday") == 0)break;
return false;
case 3:
if(strcmp(week,"Wednesday") == 0)break;
return false;
case 2:
if(strcmp(week,"Tuesday") == 0)break;
return false;
case 1:
if(strcmp(week,"Monday") == 0)break;
return false;
case 7:
if(strcmp(week,"Sunday") == 0)break;
return false;
}
return true;
}
int main()
{
int n; //定义的测试次数
int y,m, d; //年月日
cin >> n;
char week[10]; //星期几的字符串
while (n--)
{
cin >> y >> m >> d;
cin >> week;
if(back(y,m,d,week)==true)//判断返回值并进行相应的输出
cout << "YES"<< endl;
else
cout << "NO"<< endl;
}
return 0;
}
C:
#include<stdio.h>
#include<string.h>
bool back(inty, int m, int d, char w[]) //判断是否合法函数
{
if (m > 12 ||m <= 0 || y <= 0 ||d <= 0) return false; //对日期合理性进行判断
if (m == 12 &&d> 31) return false;
if (m == 11 &&d> 30) return false;
if (m == 10 &&d> 31) return false;
if (m == 9 &&d> 30) return false;
if (m == 8 &&d> 31) return false;
if (m == 7 &&d> 31) return false;
if (m == 6 &&d> 30) return false;
if (m == 5 &&d> 31) return false;
if (m == 4 &&d> 30) return false;
if (m == 3 &&d> 31) return false;
if (y % 4 != 0 || (y % 100 == 0 &&y %400 != 0)) //闰年特殊情况
{
if (m ==2 &&d > 28) return false;
}
else
{
if (m ==2 &&d > 29) return false;
}
if (m == 1 &&d> 31) return false;
if (m == 1 ||m == 2)
{
m +=12;
y--;
}
switch ((d + 2 *m + 3 * (m + 1) / 5 +y + y / 4 - y / 100 + y / 400) % 7 + 1) //基姆拉尔森计算公式W+1
{
case 1:
if(strcmp(w,"Monday") != 0) return false;
break;
case 2:
if(strcmp(w,"Tuesday") != 0) return false;
break;
case 3:
if(strcmp(w,"Wednesday") != 0) return false;
break;
case 4:
if(strcmp(w,"Thursday") != 0) return false;
break;
case 5:
if(strcmp(w,"Friday") != 0) return false;
break;
case 6:
if(strcmp(w,"Saturday") != 0) return false;
break;
case 7:
if(strcmp(w,"Sunday") != 0) return false;
break;
}
return true;
}
int main()
{
int n, y, m, d;
char w[10];
scanf("%d",&n);
while (n--)
{
scanf("%d%d%d%s", &y, &m, &d, w);
if(back(y, m, d, w) == true)
printf("YES\n");
elseprintf("NO\n");
}
return 0;
}
三、 测试数据和结果分析
输入:5//测试次数
2009 5 29 Monday//年月日星期
2009 5 30 Saturday
2007 2 29 Sunday
2014 11 14 Tuesday
2014 11 16 Sunday
输出:NO
YES
NO
NO
YES
四、总结
1.这个ACM题目倒也不是很难,虽然Runtime Error at Test 1(ACCESS_VIOLATION)
但是经过调试发现是判断语句格式的问题,虽然第一天便在 virtual studio 完美运行,但是是ACM系统给出的测试中报错Wrong Answer at Test 1,便觉得奇怪,修改了算法,还是不行,于是确定是系统输入输出先后问题。
我拿到题目时候,看到的是先输入测试次数n 然后输入n组数据,然后电脑程序处理,最后一起集中输出。这种程序要求的实现我用的是定义一个动态数组int *temp = new int[n];将每次循环返回的参数放到一个数组里面,最后遍历数组,进行相应的输出。
但是这个题目真正要求的是进行分散处理,也就是说,输入一组数据,进行处理输出。这样比较简单,不存在存储的问题。但是题目要求写的不太清楚,是我反复检查了自己的代码,添加了bool back函数,而不是如代码下面所示有太多的输出累赘语句,至少修改之后看上去比较简洁,也容易理解。
2. 利用调用函数的到函数值并进行相应的操作。我习惯于用C++进行码代码,但是C++编译在某处出现问题,于是我试着用C语言写了一个,试着提交通过了,于是我就跟踪C++些的代码,调试了好多次,最后发现问题出在case语句以及virtual studio和G++编译差异引起的
3.虽然正确答案没能用到其中处理其中输出方法,但是我了解了C++和C动态数组的申请与释放,C++用new申请,delect来释放
//C++中用指针p指向new动态分配的长度为len*sizeof(int)的内存空间
// int *p=new int[len];
// delete[] p;
而C语言用内存空间函数malloc和calloc申请,free(void*ptr)进行释放,而且函数调用分别必须包含头文件malloc.h和calloc。
4.此程序运用了大量的if和if else语句用来判断每个细节的合法性。通过这道题我更深入掌握到了if 语句和break语句,以及strcmp(s1,s2)字符串比较函数和相关函数,及C++ 和C字符串的区别和联系。