코딩테스트

[Python] 백준 1700번 - 멀티탭 스케줄링

2023. 6. 1. 17:08

문제: https://www.acmicpc.net/problem/1700

 

1700번: 멀티탭 스케줄링

기숙사에서 살고 있는 준규는 한 개의 멀티탭을 이용하고 있다. 준규는 키보드, 헤어드라이기, 핸드폰 충전기, 디지털 카메라 충전기 등 여러 개의 전기용품을 사용하면서 어쩔 수 없이 각종 전

www.acmicpc.net

Greedy 알고리즘을 이용해서 풀면 되는 문제다.

Edge case짜는게 약하다는걸 많이 느낀 문제였다.

 

내가 처음 짠 로직은 다음과 같다.

1. 일단 멀티탭 구멍 개수만큼 전자기기를 꽂는다
2. 다음 전자기기가 이미 꽂혀있는 경우, 그냥 넘어간다.
3. 다음 전자기기가 꽂혀있지 않은 경우, 무슨 전자기기를 뺄지 선택한다.   
     3-1. 꽂힌 전자기기 중 남은 전자기기에 없는 전자기기가 있으면 뺀다.   
     3-2. 꽂힌 전자기기가 모두 남은 전자기기에 있는 전자기기 인 경우, 바로 다음 숫자에 해당하는 전자기기를 뺀다.
4. 선택된 전자기기를 빼고, 다음 전자기기를 꽂는다.
5. 2-4 반복

결과적으로 3-2의 로직이 잘못됐었고, 2가지의 edge case를 빠뜨리고 있었다.

3-2의 로직은 "가장 나중에 쓰이는 전자기기를 뺀다"가 되어야 한다.

내가 빠뜨린 에지케이스는 "꽂아야 할 전자기기가 1개 남았고, 안꽂혀있는 경우"와 "1번 로직 수행 시 초반에 같은 값들이 을어올 수 있다"는 거였다.

 

해당부분을 수정한 코드는 다음과 같다.

from collections import deque

n, k = map(int, input().split())
elec_list = list(map(int, input().split()))
tab = []
answer = 0

# 초기 멀티탭 구멍 개수만큼 전자기기 꽂기
for elec in elec_list[:]:
    if len(tab) == n:
        break
    if elec not in tab:
        tab.append(elec)
        elec_list.remove(elec)

# popleft하기 위해 deque로 바꿔주기
elec_list = deque(elec_list)

while elec_list:
    # 다음 전자기기가 이미 꽂혀있는 경우, 그냥 넘어간다.
    if elec_list[0] in tab:
        elec_list.popleft()
    # 다음 전자기기가 꽂혀있지 않은 경우
    else:
        flag = 0
        # 꽂힌 전자기기 중 남은 전자기기에 없는 전자기기가 있으면
        for elec in tab:
            if elec not in elec_list:
                flag = 1
                tab.remove(elec)
                answer += 1
                tab.append(elec_list.popleft())
                break
        # 다음 전자기기가 1개 남은 경우
        if flag == 0 and len(elec_list) == 0:
            answer += 1
            del tab[0]
            tab.append(elec_list.popleft())
        # 꽂힌 전자기기가 모두 남은 전자기기에 있는 전자기기 인 경우
        elif flag == 0 and len(elec_list) != 1:
            idx = max([elec_list.index(i) for i in tab])
            tab.remove(elec_list[idx])
            answer += 1
            tab.append(elec_list.popleft())
                
print(answer)