Post
달력(백준 20207번) | Gihun Son

달력(백준 20207번)

💡 **Check Point !

( 해당사항 ✓체크 )

  1. 막힘 없이 수월하게 풀린 문제인가?

  2. 1시간이내로 풀렸던 문제인가?

  3. 1시간 이상 or 며칠을 두고 풀어봤더니 풀린 문제인가?✓

  4. 시간을 써도 도무지 풀 수 없는 문제인가?

  5. 솔루션을 찾아봤는가?


난이도 체감

  1. 최상

  2. 상✓


이해도

  1. 완벽히 이해✓

  2. 다소 헷갈리는 부분들이 있음

  3. 이해 못함

문제

수현이는 일년의 날짜가 1일부터 365일로 표시되어있는 달력을 가지고있다. 수현이는 너무나도 계획적인 사람이라 올 해 일정을 모두 계획해서 달력에 표시해놨다.

여름이 거의 끝나가자 장마가 시작되었고, 습기로 인해 달력에 표시한 일정이 지워지려고 한다. 지워지는 것을 막고자 수현이는 일정이 있는 곳에만 코팅지를 달력에 붙이려고 한다. 하지만 너무 귀찮았던 나머지, 다음과 같은 규칙을 따르기로 한다.

  • 연속된 두 일자에 각각 일정이 1개 이상 있다면 이를 일정이 연속되었다고 표현한다.
  • 연속된 모든 일정은 하나의 직사각형에 포함되어야 한다.
  • 연속된 일정을 모두 감싸는 가장 작은 직사각형의 크기만큼 코팅지를 오린다.

달력은 다음과 같은 규칙을 따른다.

  • 일정은 시작날짜와 종료날짜를 포함한다.
  • 시작일이 가장 앞선 일정부터 차례대로 채워진다.
  • 시작일이 같을 경우 일정의 기간이 긴 것이 먼저 채워진다.
  • 일정은 가능한 최 상단에 배치된다.
  • 일정 하나의 세로의 길이는 1이다.
  • 하루의 폭은 1이다.

https://upload.acmicpc.net/1a820e79-e5fc-4e4a-b7ad-efe42cfd7cdd/

위의 그림에서와 같이 일정이 주어졌다고 하자. 여기서 코팅지의 면적은 아래의 파란색 영역과 같다.

https://upload.acmicpc.net/680c1b8a-7ae1-4b00-ba41-e1c61cd64846/

이때 코팅지의 크기의 합은 3 x 8 + 2 x 2 = 28이다.

일정의 개수와 각 일정의 시작날짜, 종료날짜가 주어질 때 수현이가 자르는 코팅지의 면적을 구해보자.

Untitled

나의 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import sys
input=sys.stdin.readline
N=int(input().strip())
s_e_list=[]
for _ in range(N):
    s,e=map(int,input().strip().split())
    s_e_list.append([s,e])
s_e_list.sort()
calen=[]
max_end=0
min_start=0
answer=0
for n in range(len(s_e_list)):
    if calen:
        is_rel=False
        for i in range(len(calen)):
            if calen[i][1]+1==s_e_list[n][0]:
                calen[i][1]=s_e_list[n][1]
                max_end=max(max_end,s_e_list[n][1])
                break
            elif calen[i][1]>=s_e_list[n][0]:
                is_rel=True
        else:
            if is_rel:
                for k in range(len(calen)):
                    if calen[k][1]<s_e_list[n][0]:
                        calen[k][1]=s_e_list[n][1]
                        max_end=max(max_end,s_e_list[n][1])
                        break
                else:
                    calen.append(s_e_list[n])
                    max_end=max(max_end,s_e_list[n][1])
            else:
                answer+=(max_end-min_start+1)*len(calen)
                calen=[s_e_list[n]]
                min_start=s_e_list[n][0]
                max_end=s_e_list[n][1]
    else:
        calen.append(s_e_list[n])
        min_start=s_e_list[n][0]
        max_end=s_e_list[n][1]
    if n==len(s_e_list)-1:
        answer+=(max_end-min_start+1)*len(calen)
print(answer)
  • 위 문제는 각 일정을 [start time,end time]의 원소를 이루는 list로 유지하고, sort()한다.
  • 이어지는 일정이 있는지와 겹치는 일정이 있는지를 먼저 확인한 후, 이어지는 일정이 없고, 겹치는 일정도 없으면 현재 캘린더(calen) list를 기준으로 넓이를 구하여 더한 후 새롭게 시작한다.
  • 이어지거나 겹치는 일정이 있으면, calen에 새롭게 추가할지 아니면 이어서 추가할지를 결정한 후, 최종적으로 끝나는 일정인 max_end를 계속 유지해준다.

예외 사항들을 잘 고려해 보아야겠다.

This post is licensed under CC BY 4.0 by the author.