본문 바로가기

백준 그리디 알고리즘

[백준 1461 파이썬] 도서관 그리디 알고리즘

문제

세준이는 도서관에서 일한다. 도서관의 개방시간이 끝나서 세준이는 사람들이 마구 놓은 책을 다시 가져다 놓아야 한다. 세준이는 현재 0에 있고, 사람들이 마구 놓은 책도 전부 0에 있다. 각 책들의 원래 위치가 주어질 때, 책을 모두 제자리에 놔둘 때 드는 최소 걸음 수를 계산하는 프로그램을 작성하시오. 세준이는 한 걸음에 좌표 1칸씩 가며, 책의 원래 위치는 정수 좌표이다. 책을 모두 제자리에 놔둔 후에는 다시 0으로 돌아올 필요는 없다. 그리고 세준이는 한 번에 최대 M권의 책을 들 수 있다.

입력

첫째 줄에 책의 개수 N과, 세준이가 한 번에 들 수 있는 책의 개수 M이 주어진다. 둘째 줄에는 책의 위치가 주어진다. N은 10,000보다 작거나 같은 자연수이고, M은 10,000보다 작거나 같다. 책의 위치는 0이 아니며, 그 절댓값이 10,000보다 작거나 같다.

출력

첫째 줄에 정답을 출력한다.

풀이

책 위치의 방향은 원점을 기준으로 -와 + 두 방향이 있고

마지막 책을 갖다 놓고 다시 원점으로 올 필요가 없으므로 최소로 움직이기 위해서는 가장 멀리있는 책을

가장 마지막에 갖다 놓아야 한다.

따라서 입력값이 양수인지 음수인지 검사하여 minus, plus 리스트에 따로 추가한다.

그리고 한번에 책을 들 수 있는 개수가 있으므로 각 리스트를 정렬한다.

이제 마지막으로 둘 책을 구하기 위해 minus 리스트 가장 작은 값의 절대값과 plus리스트의 가장 큰 값을 비교한다.

가장 큰 값과 그 책을 가져다 놓을 때 같이 들 수 있는 개수만큼 리스트에서 제거한다.

나머지 책들은 책을 갖다놓고 복귀하고를 반복하면서 정리하면 된다.

따라서 반복문의 스텝을 한번의 책을 들 수 있는 개수 m으로 두고 책의 위치에 갔다 와야 하기 때문에 2씩 곱해주어

ans에 더한다.

마지막으로 아까 구했던 last_value를 더해주면 된다.

 

import sys
n, m = map(int, sys.stdin.readline().rstrip("\n").split())
nums = list(map(int, sys.stdin.readline().rstrip("\n").split()))
minus = []
plus = []
for num in nums:
    if(num<0):
        minus.append(num)
    else:
        plus.append(num)
minus = sorted(minus)
plus = sorted(plus,reverse=True)
minus_num=0
if(len(minus)>0):
    minus_num = min(minus)
plus_num = 0
if(len(plus)>0):
    plus_num = max(plus)
if(abs(minus_num) >= abs(plus_num)):
    last_value = minus_num
    for _ in range(m):
        if (len(minus) > 0):
            minus.remove(minus[0])
else:
    last_value = plus_num
    for _ in range(m):
        if (len(plus) > 0):
            plus.remove(plus[0])
ans=0
for i in range(0,len(minus),m):
    ans+=abs(minus[i])*2
for i in range(0,len(plus),m):
    ans+=plus[i]*2
ans += abs(last_value)
print(ans)