여름의 서재

[SWEA] 1952_수영장 (DP 이용) 본문

알고리즘/SWEA

[SWEA] 1952_수영장 (DP 이용)

엉아_ 2021. 9. 24. 23:10
728x90

📕 문제

김 프로는 수영장을 이용한다.
김 프로는 지출이 너무 많아 내년 1년 동안 각 달의 이용 계획을 수립하고 가장 적은 비용으로 수영장을 이용할 수 있는 방법을 찾고 있다.
수영장에서 판매하고 있는 이용권은 아래와 같이 4 종류이다.
   ① 1일 이용권 : 1일 이용이 가능하다.
   ② 1달 이용권 : 1달 동안 이용이 가능하다. 1달 이용권은 매달 1일부터 시작한다.
   ③ 3달 이용권 : 연속된 3달 동안 이용이 가능하다. 3달 이용권은 매달 1일부터 시작한다.
       (11월, 12월에도 3달 이용권을 사용할 수 있다 / 다음 해의 이용권만을 구매할 수 있기 때문에 3달 이용권은 11월, 12월, 1윌 이나 12월, 1월, 2월 동안 사용하도록 구매할 수는 없다.)
   ④ 1년 이용권 : 1년 동안 이용이 가능하다. 1년 이용권은 매년 1월 1일부터 시작한다.
각 달의 이용 계획은 [Table 1]의 형태로 수립된다.

  1 2 3 4 5 6 7 8 9 10 11 12
이용 계획 0 0 2 9 1 5 0 0 0 0 0 0

[Table 1]


이용 계획에 나타나는 숫자는 해당 달에 수영장을 이용할 날의 수를 의미한다.

각 이용권의 요금과 각 달의 이용 계획이 입력으로 주어질 때,
가장 적은 비용으로 수영장을 이용할 수 있는 방법을 찾고 그 비용을 정답으로 출력하는 프로그램을 작성하라.


[예시]

수영장에서 판매하는 1일 이용권, 1달 이용권, 3달 이용권, 1년 이용권의 요금은 각각 10원, 40원, 100원, 300원이다.
이 때 수영장을 이용할 수 있는 방법은 [Table 2]와 같이 다양한 경우를 생각할 수 있다.

이용하는 방법 이용권 비용
1번 경우)
모두 1일 이용권으로만 이용한다.
1일 이용권 17 :
17 * 10 = 170
170
2번 경우)
모두 1달 이용권으로만 이용한다.
1달 이용권 4 :
4 * 40 = 160
160
3번 경우)
3월은 1일 이용권으로 이용하고
4, 5, 6월은 3달 이용권으로 이용한다.
1일 이용권 2, 3달 이용권 1 :
2 * 10 + 1 * 100 = 120
120
4번 경우)
3월과 5월은 1일 이용권으로 이용하고
4월과 6월은 1달 이용권으로 이용한다.
1일 이용권 3, 1달 이용권 2 :
3 * 10 + 2 * 40 = 110
110
5번 경우)
1년 이용권으로 이용한다.
1년 이용권 1 :
1 * 300 = 300
300

[Table 2]


다른 경우도 가능하지만, 가장 적은 비용으로 수영장을 이용한 경우는 4번 경우이다.
따라서, 정답은 110이 된다.


[제약 사항]
1. 시간 제한 : 최대 50개 테스트 케이스를 모두 통과하는 데 C/C++/Java 모두 3초
2. 모든 종류의 이용권 요금은 10 이상 3,000 이하의 정수이다.
3. 각 달의 이용 계획은 각 달의 마지막 일자보다 크지 않다.


[입력]

입력의 맨 첫 줄에는 총 테스트 케이스의 개수 T가 주어지고, 그 다음 줄부터 T개의 테스트 케이스가 주어진다.
각 테스트 케이스의 첫 번째 줄에는 1일 이용권의 요금, 1달 이용권의 요금, 3달 이용권의 요금, 1년 이용권의 요금이 순서대로 한 칸씩 띄고 주어진다.
그 다음 줄에는 1월부터 12월까지의 이용 계획이 주어진다.

 

[출력]

테스트 케이스 개수만큼 T개의 줄에 각각의 테스트 케이스에 대한 답을 출력한다.
각 줄은 "#t"로 시작하고 공백을 하나 둔 다음 정답을 출력한다. (t는 1부터 시작하는 테스트 케이스의 번호이다)
출력해야 할 정답은 이용 계획대로 수영장을 이용하는 경우 중 가장 적게 지출하는 비용이다.

 

💡 풀이법

1. 각 달까지의 최소값을 담을 리스트 dp를 담는다.

2. 1월달은 1달권을 끊을 경우와 1일 이용권을 끊을 경우 두 가지밖에 없기 때문에 둘중 작은 수를 dp[0]에 저장해준다.

3. 2월달도 1달권을 끊는 경우와 1일 이용권을 끊는 경우 두 가지 중에 고르고 1월달 요금까지 더해서 dp[1]에 저장한다.

3. 이후에는 3달권을 끊을 경우가 추가로 발생할 수 있기 때문에 세달 전의 요금에 3달 이용권 요금을 더한 요금을 추가해서 3가지 경우 중 가장 작은 경우를 dp에 저장해준다.

 

T = int(input())
for tc in range(1, T+1):
    fees = list(map(int, input().split()))
    schedules = list(map(int, input().split()))

    dp = [0]*12
    dp[0] = min(fees[0]*schedules[0], fees[1])
    dp[1] = dp[0] + min(fees[0]*schedules[1], fees[1])

    for i in range(2, 12):
        dp[i] = min(dp[i-3]+fees[2], dp[i-1]+fees[0]*schedules[i], dp[i-1]+fees[1])

    ans = min(dp[11], fees[3])
    print('#{} {}'.format(tc, ans))
Comments