본문 바로가기

알고리즘/소프티어

[파이썬] Softeer 연습문제 #18. 택배 마스터 광우 완벽해설

문제

 

 

https://softeer.ai/practice/6273

 

Softeer - 현대자동차그룹 SW인재확보플랫폼

여름 휴가를 떠나기 위해 용돈이 필요했던 광우는 H택배 상하차 아르바이트를 지원 했다. 광우는 평소에 운동을 하지않아 힘쓰는 데에 자신이 없었지만, 머리 하나 만큼은 비상해 택배가 내려오

softeer.ai

 

 

 

해설

 

이 문제는 레일의 순서의 모든 경우의 수를 만들고, 이 모든 경우의 수에 따라 담은 무게를 하나하나 리스트에 담은 후, 그렇게 모든 경우의 수에 대해서 일을 진행시킨 후 리스트에서 최소값을 출력해주게 되면 결국 "일을 해야 하는 최소한의 택배 무게"를 구할 수 있게 된다.

 

이를 위해 가장 먼저 해야될 일은 수열을 통해 레일의 순서의 모든 경우의 수를 구해야 한다.

 

from itertools import permutations

# 레일의 개수 N, 택배 바구니의 무게 M, 그리고 일의 시행 횟수 K를 담기.
N, M, K = map(int, sys.stdin.readline().split())
# 택배 레일의 전용 무게 리스트를 저장한다.
rails = list(map(int, sys.stdin.readline().split()))
# 모든 경우의 수에 대해 처리한 무게를 모두 담을 리스트.
weights_list = []

# 택배 레일의 전용 무게로 모든 가능한 수열을 얻어낸다.
rails_permutation = permutations(rails, N)

 

이는 itertools 라는 라이브러리에서 permutations 라는 함수를 통해 할 수 있다. 사용법은 permutations(리스트, 수열의 길이) 처럼 첫번째 변수로는 수열을 만들 리스트, 그리고 두번째 변수로는 수열의 갯수를 넣어준다.

 

 

따라서 이 경우 레일의 갯수는 N개이기 때문에 permutations(레일 리스트, N) 이렇게 변수를 넣어주면 해당 레일을 토대로 N개로 이루어진 모든 수열을 구해주게 된다.

 

그 다음에 작성해야 할 코드는 한 경우의 수에 대해 작업을 진행하는 코드를 작성해야 한다. 

 

def work(rail, N, M, K):
  # 물류 레일에서 서있는 위치를 저장하기 위한 변수
  cnt = 0
  # 택배 바구니에 담은 무게를 측정할 변수
  weights = 0
  # 일의 시행 횟수동안 처리한 모든 무게를 저장할 변수
  sum_weights = 0

  # K만큼 일을 시행한다.
  for i in range(K):
    # 각각의 일은 무게 M이 담길 때까지 계속 무한 진행된다.
    while True:
      # 바구니에 cnt 번째 레일의 무게를 담는다.
      weights += rail[cnt]
      # 만약 바구니에 M 이상의 무게가 찼을 경우
      if (weights > M):
        # 그 이전의 무게를 제거해주고
        weights -= rail[cnt]
        # 누적 무게량을 sum_weights에 더해주고
        sum_weights += weights
        # 바구니를 초기화 시켜주고
        weights = 0
        # 한번의 일을 마친다.
        break
      # 만약 무게가 차지 않았을 경우 그 다음 레일로 이동한다.
      cnt = (cnt + 1) % N
  # 일의 시행 횟수동안 처리한 모든 무게를 출력한다.
  return sum_weights

 

이는 위와 같이 작성할 수 있다.

 

마지막으로 모든 경우의 수에 대해서 위의 작업을 진행하는 코드를 하나하나 작성해준 후, 한번 한번의 작업에서의 무게를 기록해주는 코드를 작성하게 되는데,

 

# 모든 레일의 수열 경우의 수에 따라
for rail in rails_permutation:
  # K번의 일을 돌리고, 그 무게를 weights_list에 담는다.
  weights_list.append(work(rail, N, M, K))

 

위와 같이 작성할 수 있다.

 

마지막으로 weights_list에 담은 모든 요소들 중에서 가장 최소값을 출력해주면 그 최소값이 결국 일을 해야하는 최소한의 택배 무게가 된다.

 

# 마지막으로 weights_list 중 최소값을 출력한다. (이는 광우가 일 해야하는 최소한의 택배 무게가 된다.)
print(min(weights_list))

 

코드는 위와 같다.

 

그리고 위의 모든 코드를 모두 하나로 작성하면 이 문제를 어려움 없이 풀 수가 있다.

 

 

코드

 

import sys
from itertools import permutations

# 레일의 개수 N, 택배 바구니의 무게 M, 그리고 일의 시행 횟수 K를 담기.
N, M, K = map(int, sys.stdin.readline().split())
# 택배 레일의 전용 무게 리스트를 저장한다.
rails = list(map(int, sys.stdin.readline().split()))
# 모든 경우의 수에 대해 처리한 무게를 모두 담을 리스트.
weights_list = []

# 택배 레일의 전용 무게로 모든 가능한 수열을 얻어낸다.
rails_permutation = permutations(rails, N)

def work(rail, N, M, K):
  # 물류 레일에서 서있는 위치를 저장하기 위한 변수
  cnt = 0
  # 택배 바구니에 담은 무게를 측정할 변수
  weights = 0
  # 일의 시행 횟수동안 처리한 모든 무게를 저장할 변수
  sum_weights = 0

  # K만큼 일을 시행한다.
  for i in range(K):
    # 각각의 일은 무게 M이 담길 때까지 계속 무한 진행된다.
    while True:
      # 바구니에 cnt 번째 레일의 무게를 담는다.
      weights += rail[cnt]
      # 만약 바구니에 M 이상의 무게가 찼을 경우
      if (weights > M):
        # 그 이전의 무게를 제거해주고
        weights -= rail[cnt]
        # 누적 무게량을 sum_weights에 더해주고
        sum_weights += weights
        # 바구니를 초기화 시켜주고
        weights = 0
        # 한번의 일을 마친다.
        break
      # 만약 무게가 차지 않았을 경우 그 다음 레일로 이동한다.
      cnt = (cnt + 1) % N
  # 일의 시행 횟수동안 처리한 모든 무게를 출력한다.
  return sum_weights

# 모든 레일의 수열 경우의 수에 따라
for rail in rails_permutation:
  # K번의 일을 돌리고, 그 무게를 weights_list에 담는다.
  weights_list.append(work(rail, N, M, K))

# 마지막으로 weights_list 중 최소값을 출력한다. (이 값은 결국 광우가 일 해야하는 최소한의 택배 무게가 된다.)
print(min(weights_list))

 

 

결과