[JAVA][백준 16463] 13일의 금요일

June Park·2021년 10월 4일
0

백준 문제풀이

목록 보기
3/3
post-thumbnail

문제

재운이는 이 구역의 소문난 오컬트 매니아다. 늘 도서관에서 오컬트 서적을 읽고 외계문물 스터디에 참여하던 재운이는 어느 날 엄청난 소문을 듣게 되었다. 소문의 정체는 지구의 미래에 관한 예언이었는데, 그 예언에 따르면 2019년부터 다가오는 13일의 금요일의 수를 세지 않으면 지구가 멸망할 수 있다고 한다. 평소 배려심이 넘치는 재운이는 자신 뿐만 아니라 자신의 후세들을 위해 앞으로 기원 후 100,000년 까지 누적되는 13일의 금요일의 수를 매 년도마다 기록하기로 했다. 하지만 계산에 약한 재운이는 온갖 계산을 우리에게 떠맡겼다. 재운이를 도와 2019년부터 N년까지 누적되는 13일의 금요일의 수를 계산하여 알려주자.

입력

첫째 줄에 정수 N이 입력된다. (2019 ≤ N ≤ 100,000)

출력

첫째 줄에 2019년부터 N년까지 누적되는 13일의 금요일의 수를 출력한다


✨ Methodology

매년 돌면서, 각 월마다 13일이 금요일인지 확인하기


이 문제를 풀기 위해서 2019년 1월 1일의 요일을 확인해보았다. 1월 1일은 화요일로, 요일 배열을 만들 때 중요하게 작용한다 (직접 찾아봤는데 힌트에 써있었다...)

1. 윤년

이 문제를 풀기 위해서는 윤년에 대해서 이해할 필요가 있다.
2월은 28일 혹은 29일까지 있는데, N이 년도일 때,

  • N % 4 == 0 이면 윤년이다 (29일)
  • N % 4 == 0 이지만, N % 100 == 0이면 윤년이 아니다 (28일)
  • 위 조건을 만족하지만, N % 400 == 0 이면 윤년이다 (29일)

위 조건을 코드로 표현하면, 아래와 같다.

if((N % 4==0 && N % 100!=0)||N % 400==0 )

2. 일수 배열과 요일 배열

각 월별 일수를 저장한 배열과 요일 배열이 필요하다.
일수 배열은

static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};

로 표현하였다.

  • 0은 dummy data로 총 일수를 구하려면 그 전달까지의 full days와 해당 월의 13일을 더해야 하기 때문에 매 1월 13일을 편하게 구하기 위해서 넣어주었다. 요일맞추기에서 자세하게 설명하였다.
  • 요일 배열은 화요일에서 부터 시작하기 때문에 가장 첫 원소로 월요일을 넣어주었다. 이 역시, 링크텍스트에서 설명하였지만 간단히 설명하자면 1월 1일이 월요일이라면 1월 8일도 월요일이 된다. 즉, 요일배열[days%7==1]=월요일이 되므로, 해당 문제에서는 1월 1일이 화요일이기 때문에 요일배열[1]이 화요일이 되기 위해선 0번째 원소는 월요일이 되어야 한다.
  • 이 문제에서는 13일이 금요일인지를 확인하는 문제이기 때문에, 요일배열[전달까지의 총 일수+13일 % 7 ]이 금요일인지를 확인하면 된다.

3. for loop

  • freaky_fridays라는 변수를 두어, 만일 13일이 금요일일 경우 ++시켜 13일이 금요일인 횟수를 카운트 해주었다.
  • 브루트포스 방식으로 해당 2019년 부터 N 년도 까지 outer loop를 돌려 주었고, 해당 년도가 윤년인지 평년인지 계산하여 만약 윤년이라면 일수배열[2월달]을 29일로 설정 아니라면 28일로 설정하였다.
for(int i = 2019; i<=N ; i++) {//년
	if((i%4==0 && i%100!=0)||i%400==0 ){//윤년일 경우 ->2월에 +1
	days[2] = 29;}
	else {days[2]=28;}//윤년이 아닐 경우
	//inner for loop
}
  • outer loop에서 해당 년도에 대한 루프를 돌렸기 때문에, inner loop를 생성하여 월별로 13일이 금요일인지 아닌지 확인하였다.
for(int i = 2019; i<=N ; i++) {//년
	if((i%4==0 && i%100!=0)||i%400==0 ){//윤년일 경우 ->2월에 +1
	days[2] = 29;}
	else {days[2]=28;}//윤년이 아닐 경우

	for(int j = 1; j<=12;j++) {//월
		if(date[(total_days+13)%7]==5) {//13해당 월의 13일이 금요일인가?
		//System.out.println(i+"년"+j+"월"); //몇년 몇월달의 13일이 금요일인지 확인 가능
		freaky_fridays++;} //13일이 금요일이면 카운트 ++
		total_days+=days[j];}//확인이 끝났다면 해당 월의 일수를 총 일수에 더한다		
  }

총 일수에 13을 더하고 금요일인지 확인한 후, 해당 월에 남은 일수를 더할 수도 있지만 개인적으로 직접 더하지 않고 전월까지의 총 일수+13일 % 7 로 이번달의 13일이 금요일인지 확인한 후, 해당 월의 총 일수를 더하는 방식이 더 쉽게 느껴져서 위처럼 코딩하였다.

✨ 전체 소스 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
public class BOJ_16463_13일의금요일 {
static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
static int[] date = {1,2,3,4,5,6,7};//월~일 : 1월 1일이 화요일임
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());//2019~N년
		int freaky_fridays = 0;//13일의 금요일
		int total_days = 0;
		for(int i = 2019; i<=N ; i++) {//년
			if((i%4==0 && i%100!=0)||i%400==0 ){//윤년일 경우 ->2월에 +1
				days[2] = 29;
			}
			else {days[2]=28;}//윤년이 아닐 경우
			//Base Case:
			for(int j = 1; j<=12;j++) {//월
				if(date[(total_days+13)%7]==5) {
				//System.out.println(i+"년"+j+"월");
				freaky_fridays++;}
				total_days+=days[j];}
		}
		System.out.println(freaky_fridays);
	}

}

0개의 댓글