알고리즘/알고리즘_백준

[Python][백준] 1931. 회의실 배정/ 그리디,정렬(S1)

Jerry_K 2024. 7. 19. 12:00

링크🔗

https://www.acmicpc.net/problem/1931


🗒️파이썬 코드 풀이

N = int(input())
lst = []

for _ in range(N):
    start,end = map(int,input().split())
    lst.append((start,end))
lst.sort()
rs_lst = [lst[0]]

for i in range(1,N):
    if rs_lst[-1][1] > lst[i][0]:
        if rs_lst[-1][1] > lst[i][1]:
            rs_lst.pop()
            rs_lst.append(lst[i])
    elif rs_lst[-1][1] <= lst[i][0]:
         rs_lst.append(lst[i])

print(len(rs_lst))

 

1. 먼저 마구잡이의 입력을 (strart 기준)정렬해준다. 

 

2. 비교 대상을 크게 2가지로 나눈다. 

1) end(현재) - strart(다음)
2) end(현재) - end(다음)

end(현재) > strart(다음)인 경우는 케줄이 겹치는 상황이다. 
이럴때는 end(현재) - end(다음)를 비교하고,
기존 스케줄을 빼고 더 작은 스케줄을 rs_lst에 넣는다.

end(현재) < strart(다음)인 경우는 겹치지 않는 새로운 스케줄이므로,
결과 리스트에 넣는다. 

 

위의 조건을 코드로 작성 한 것이다.

 if rs_lst[-1][1] > lst[i][0]: # end(현재)-strart(다음)
    if rs_lst[-1][1] > lst[i][1]: # end(현재)-end(다음)
        rs_lst.pop() # 기존 스케줄 제거
        rs_lst.append(lst[i])  # 시간이 더 작은 스케줄 추가
elif rs_lst[-1][1] <= lst[i][0]: # end(현재)-strart(다음)
     rs_lst.append(lst[i]) # 새로운 스케줄 추가

 

아래의 풀이를 보면 좀 더 이해하기 쉬울 것이다.

ex) 
[(0, 6), (1, 4), (2, 13), (3, 5), (3, 8), (5, 7), (5, 9), (6, 10), (8, 11), (8, 12), (12, 14)]

1) (0,6) - (1,4) 
endpoint 부분에 작은 값이 나오는게 무조건 유리하다. 
이 경우는 기존 endpoint가 다음 endpoint보다 크기때문에,
rs_lst를 (1,4)로 새로 업데이트 해준다. 

2) (1,4) - (2, 13) - (3, 5) - (3, 8)
기존 endpoint에서 다음 startpoint같거나 큰 경우 업데이트 한다.
이 경우는 조건에 만족하는 것들이 없어 업데이트를 안한다.


3) (5, 7) 
이 경우가 기존 endpoint에서 다음 startpoint가 같거나 큰 경우다.
rs_lst에 추가로 (5, 7)를 넣어준다

 

 

🗒️다른 파이썬 코드 풀이

N = int(input())
lst = []
ans = 1
for _ in range(N):
    start,end = map(int,input().split())
    lst.append((start,end))
lst.sort(key=lambda x: (x[1],x[0]))
endpoint = lst[0][1]
for i in range(1,N):
    if lst[i][0]>= endpoint:
        endpoint = lst[i][1]
        ans += 1
print(ans)

 

좀 더 간단하게 생각해도 된다. 

 

endpoint가 작은게 무조건 유리하기 떄문에,

이 경우는 끝나는 시간은 기준으로 sort 해준다. 

 

그리고 다음 startpoint가 기존 endpoint보다 큰 경우에 ans + 1을 한다.

 

📌  문제 코멘트

 N의 크기가 100,000 이하로, 이런 경우 매우 제한된 알고리즘만 가능하다.

따라서 DFS,BFS 같은 것은 생각도 하면 안된다.

 

그래서 맨 처음 DP로 해결하려고 했는데, 감이 잘 안잡혔다. 

DP가 안될 때는  Greedy를 생각해보고, Greedy가 안될 때는 DP를 생각해보자. 

 

처음에는 좀 복잡했는데, 하나 하나 손으로 써보니까 감이 잡혔고,

어떤 식으로 조건을 걸어둘지 생각을 하고 코드를 작성했다.

괜히 시간을 아끼려고 바로 코드 작성하면 더 힘들어진다 ... 

 

📚문제

한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다. 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자. 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다. 회의의 시작시간과 끝나는 시간이 같을 수도 있다. 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다.

입력

첫째 줄에 회의의 수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N+1 줄까지 각 회의의 정보가 주어지는데 이것은 공백을 사이에 두고 회의의 시작시간과 끝나는 시간이 주어진다. 시작 시간과 끝나는 시간은 231-1보다 작거나 같은 자연수 또는 0이다.

출력

첫째 줄에 최대 사용할 수 있는 회의의 최대 개수를 출력한다.

예제 입력 1 복사

11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14

예제 출력 1 복사

4

힌트

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.