어려운 문제가 아닌데 함정이 이곳저곳 있었다.
- 받은 두 날짜를 일 수로 변환해 저장한다.
- 뺄셈한 후 사이에 존재하는 윤년의 개수만큼 더해준다.
- 디데이가 1000년 이상이면 gg를 아니면 디데이를 출력한다.
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
// 일수로 바꿔서 계산한 후 윤년이 있던 개수만큼 답에 증가한다.
struct date {
int year;
int month;
int day;
};
int months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int leapyear(date d1, date d2) { // 윤년 개수 구하기
int cnt = 0;
if (d1.month > 2) { d1.year++; }
if (d2.month > 2) { d2.year++; }
for (int i = d1.year; i < d2.year; i++) {
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) { cnt++; }
}
return cnt;
}
int yeartoday(date d) { // 년월일을 일수로 바꾸기
int date = 0;
date += d.year * 365;
for (int i = 0; i < d.month - 1; i++) { date += months[i]; }
date += d.day;
return date;
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
date d, dday;
int day1, day2, ans = 0;
cin >> d.year >> d.month >> d.day;
cin >> dday.year >> dday.month >> dday.day;
day1 = yeartoday(d);
day2 = yeartoday(dday);
ans = day2 - day1;
ans += leapyear(d, dday);
if (ans >= 365243) { cout << "gg"; } // 1년은 365.2422일
else { cout << "D-" << ans; }
return 0;
}
윤년 조건문과 1000년에서 애를 먹었었다.
윤년의 조건은 다음과 같다.
- 서력기원 연수가 4로 나누어떨어지는 해는 우선 윤년으로 한다. (2004년, 2008년, …)
- 100으로 나누어떨어지는 해는 평년으로 한다. (2100년, 2200년, …)
- 400으로 나누어떨어지는 해는 다시 윤년으로 한다. (1600년, 2000년, …)
조건문을 만들 때 "4로 떨어져야하고.. 100으로는 떨어지면 안 되고.. 근데 400으로는 떨어져야 하고.." 하면서 아래와 같은 식을 만들게 되는데, 맞는 것 같지만 이 식은 틀렸다.
if (year % 4 == 0 && year % 100 != 0 && year % 400 == 0)
해당 조건문을 컴퓨터가 읽는 순서에서 이유를 알 수 있다. year가 100인 경우, 첫 번째 조건은 통과하지만 두 번째 AND 조건인 year % 100 != 0
에서 FALSE가 되어 다음 조건은 검사도 하지 않고 IF문을 나가버린다.
위의 3개의 조건을 다시 2개의 조건으로 정리할 수가 있는데,
- 4로 나누어떨어지면서 100으로 나누어떨어지지 않으면 윤년이다.
- 400으로 나누어떨어지는 해는 윤년이다.
위 조건을 조건문으로 만들면 아래와 같다.
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
이렇게 작성해야 윤년을 구할 수 있다.
1년은 평균적으로 365.2422일이다.
1000년이라고 하면 단순하게 1000 * 365일 이라고 생각할 수 있지만, 정확한 1년은 365일이 아니라 365.2422일 이었다......
소수점 자리는 올림해서 1000년은 365243으로 계산한다.