一、日期差值
1、題目和要求
時間限制:1s,內存限制:32MB,特殊判題:否
2、總結
1)閏年的判斷規則:當年數不能被100整除且能被4整除則爲閏年,或者其能被
400整除時也是閏年。某種情況下,可能出現兩個閏年相隔 8 年。
2)可以採用宏定義函數的方式判斷是否是閏年,宏定義函數的處理過程是:預處理器用複製宏代碼的方式代替函數的調用,省去了函數壓棧退棧過程,提高了效率。
#define ISYEAP(x) x%100!=0 && x%4==0 || x%400==0 ? 1:0
3)輸入技巧:輸入爲連續的八位數來表示日期,使用 %4d讀取前四位,使用 %2d%2d讀取其它後四位。省去了字符串處理。
scanf("%4d%2d%2d",&d.year,&d.month,&d.day);
4)由於需要計算輸入時間與規定的原點時間(規定爲0年0月0日)之間相差的天數,計算量較大,因此考慮對數據採用預處理的方式:
“在程序真正開始處理輸入數據之前,預處理出所有日期與原點日期之間的天數差並保存起來。當數據真正開始輸入時,只需要用0 (1) 的時間複雜度將保存的數據讀出,稍加處理便能得到答案。”
假定我們計算5001年12月31日之前的所有日期與原點日期之間的天數差,使用buf[5001][13][32]
三維數組保存計算結果。這樣就可以直接使用下標buf[year][month][day]
得到year年month月day日與原點日期之間的天數差。
在“4)”中,有以下幾點需要注意:
- 採用預處理是空間換時間的重要手段(保存預處理所得數據所需的內存來換取實時處理所需要的時間消耗),酌情使用。
buf[5001][13][32]
這個數組比較耗費內存,因此需在函數體外定義,即定義成全局變量,或在函數中使用malloc等函數動態申請變量空間。- 這種方法的一個缺點是,當輸入日期爲5002年的某一天時,將不能得出正確結果。
由於需要耗費大量的內存,若在main函數(其它函數也一樣(之中定義該數組,其函數所可以使用的棧空間將不足以提供如此龐大的內存,出現棧溢出,導致程序異常終止。所以,凡是涉及此類需要開闢大量內存空間的情況,都必須參照以上方法。
3、思路
考察了日期類問題中最基本的問題——求分別以兩個特定日期爲界的日期區間的長度。解決這類區間問題有一個統一的思想:把原區間問題統一到起點確定的區間問題上。
在該例中,把問題統一到特定日期與一個原點時間的天數差,當要求兩個特定的日期之間的天數差時,只要將它們與原點日期的天數差相減,便能得到這兩個特定日期之間的天數差(必要時加絕對值)。
4、代碼
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
struct Date{
int year;
int month;
int day;
Date(){
year=0;month=0;day=0;
}
};
int month(int i){
switch(i){
case 1:return 31;
case 2:return 28;
case 3:return 31;
case 4:return 30;
case 5:return 31;
case 6:return 30;
case 7:return 31;
case 8:return 31;
case 9:return 30;
case 10:return 31;
case 11:return 30;
case 12:return 31;
}
}
int calDays(Date *d){
int days=0;
int y_run = d->year/4,y_ping = d->year - y_run;
//年
days = y_run*366+y_ping*365;
//月
if(d->month>2){
for(int i=1;i<=d->month;i++){
days += month(i);
}
if((d->year % 4 ==0 && d->year % 100!=0) || d->year % 400 ==0){
days += 1;
}
}
//日
days += d->day;
return days;
}
int main(){
Date d1,d2;
string s1,s2;
int i=0;
// cin>>s1>>s2;
s1="20110412";
s2="20110422";
while(i<4) d1.year=d1.year*10+s1[i++];
while(i<6) d1.month=d1.month*10+s1[i++];
while(i<8) d1.day=d1.day*10+s1[i++];
i=0;
while(i<4) d2.year=d2.year*10+s2[i++];
while(i<6) d2.month=d2.month*10+s2[i++];
while(i<8) d2.day=d2.day*10+s2[i++];
cout<<abs(calDays(&d1)-calDays(&d2))+1<<endl;
}
#include <stdio.h>
#include <iostream>
#include <cmath>
using namespace std;
#define ISYEAP(x) x%100!=0 && x%4==0 || x%400==0 ? 1:0
int buf[5001][13][32];
int dayOfMonth(int i,int isyeap){
switch(i){
case 1:return 31;
case 2:
if(isyeap){
return 29;
}
return 28;
case 3:return 31;
case 4:return 30;
case 5:return 31;
case 6:return 30;
case 7:return 31;
case 8:return 31;
case 9:return 30;
case 10:return 31;
case 11:return 30;
case 12:return 31;
}
}
struct Date{
int year;
int month;
int day;
Date(){
year=0;month=0;day=0;
}
void nextDay(){
day++;
if(day>dayOfMonth(month,ISYEAP(year))){
day=1;month++;
if(month>12){
month=1;year++;
}
}
}
};
int main(){
Date d1,d2;
string s1,s2;
int days=0;
d1.day=1;d1.month=1;d1.year=0;
while(d1.year!=5001){
buf[d1.year][d1.month][d1.day]=days;
d1.nextDay();
days++;
}
//d1.year=2011;d1.month=4;d1.day=12;
//d2.year=2011;d2.month=4;d2.day=22;
scanf("%4d%2d%2d",&d1.year,&d1.month,&d1.day);
scanf("%4d%2d%2d",&d2.year,&d2.month,&d2.day);
printf("%d\n",abs(buf[d1.year][d1.month][d1.day]-buf[d2.year][d2.month][d2.day]))+1;
return 0;
}
二、Day of Week
1、題目和要求
時間限制:1s,內存限制:32MB,特殊判題:否
2、總結
(4 + abs(calDays(&d1) - calDays(&d2)))%7
還可以寫成 ((4 + calDays(&d1) - calDays(&d2))%7 + 7)%7
3、思路
按照上面例題的解題思路:知道今天星期幾,知道今天和輸入天數相差幾天。根據星期以7天爲一週期,從而求得輸入日期是星期幾。
4、代碼
#include <cmath>
#include <string>
#include <iostream>
using namespace std;
struct Date{
int year;
int month;
int day;
void setMonth(string s){
if(s == "January") month = 1;
else if(s == "February")month = 2;
else if(s == "March")month = 3;
else if(s == "April")month = 4;
else if(s == "May")month = 5;
else if(s == "June")month = 6;
else if(s == "July")month = 7;
else if(s == "August")month = 8;
else if(s == "September")month = 9;
else if(s == "October")month = 10;
else if(s == "November")month = 11;
else if(s == "December")month = 12;
else month=0;
}
};
int month(int i){
switch(i){
case 1:return 31;
case 2:return 28;
case 3:return 31;
case 4:return 30;
case 5:return 31;
case 6:return 30;
case 7:return 31;
case 8:return 31;
case 9:return 30;
case 10:return 31;
case 11:return 30;
case 12:return 31;
}
}
int calDays(Date *d){
int days=0;
int y_run = d->year/4,y_ping = d->year - y_run;
//年
days = y_run*366+y_ping*365;
//月
if(d->month>2){
for(int i=1;i<=d->month;i++){
days += month(i);
}
if((d->year % 4 ==0 && d->year % 100!=0) || d->year % 400 ==0){
days += 1;
}
}
//日
days += d->day;
return days;
}
int main(){
Date d1,d2;
string m;
d1.year=2020;d1.month=6;d1.day=4;
cin>>d2.day>>m>>d2.year;
d2.setMonth(m);
//2020.6.4 is Thursday
switch((4+abs(calDays(&d1) - calDays(&d2)))%7){
case 4: printf("Thursday\n");break;
case 5: printf("Friday\n");break;
case 6: printf("Saturday\n");break;
case 0: printf("Sunday\n");break;
case 1: printf("Monday\n");break;
case 2: printf("Tuesday\n");break;
case 3: printf("Wednesday\n");break;
}
return 0;
}