백준 15486 파이썬 문제 풀이
- CS/BOJ
- 2021. 6. 23.
문제
상담원으로 일하고 있는 백준이는 퇴사를 하려고 한다. 오늘부터 N+1일째 되는 날 퇴사를 하기 위해서, 남은 N일 동안 최대한 많은 상담을 하려고 한다. 백준이는 비서에게 최대한 많은 상담을 잡으라고 부탁을 했고, 비서는 하루에 하나씩 서로 다른 사람의 상담을 잡아놓았다.각각의 상담은 상담을 완료하는데 걸리는 기간 Ti와 상담을 했을 때 받을 수 있는 금액 Pi로 이루어져 있다.
N = 7인 경우에 다음과 같은 상담 일정표를 보자.상담을 하는데 필요한 기간은 1일보다 클 수 있기 때문에, 모든 상담을 할 수는 없다. 예를 들어서 1일에 상담을 하게 되면, 2일, 3일에 있는 상담은 할 수 없게 된다. 2일에 있는 상담을 하게 되면, 3, 4, 5, 6일에 잡혀있는 상담은 할 수 없다.
또한, N+1일째에는 회사에 없기 때문에, 6, 7일에 있는 상담을 할 수 없다.퇴사 전에 할 수 있는 상담의 최대 이익은 1일, 4일, 5일에 있는 상담을 하는 것이며, 이때의 이익은 10+20+15=45이다. 상담을 적절히 했을 때, 백준이가 얻을 수 있는 최대 수익을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N (1 ≤ N ≤ 1,500,000)이 주어진다.
둘째 줄부터 N개의 줄에 Ti와 Pi가 공백으로 구분되어서 주어지며, 1일부터 N일까지 순서대로 주어진다. (1 ≤ Ti ≤ 50, 1 ≤ Pi ≤ 1,000)
출력
첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.
문제접근방법
일단 이 문제는 브루트포스로 접근할 수가 없다. 왜냐하면 N이 150만으로, 완전탐색일 경우 대부분 시간복잡도가 N^2 이상이니 완전탐색으로 접근할 수 없다. 따라서, 그리디 알고리즘 혹은 다이나믹 프로그래밍으로 접근해서 확인해봐야 한다. 나는 다이나익 프로그래밍으로 접근했다.
먼저 범위를 정확하게 설정해야했다. d라는 리스트를 선언했는데, 이는 d일까지 벌어둔 최대한의 금액이다. 그리고 범위는 N+1일까지 해야했는데, 왜냐하면 마지막 날에 하루짜리 일을 했다면 이 역시 돈을 받을 수 있기 때문이다.
그렇다면 다이나믹 프로그래밍의 부분 문제는 어떻게 찾을 수 있을까?
먼저 1일차를 본다. 1일차는 일을 안하기 때문에 무조건 0원이다. 단, 1일차에 일을 하는 경우가 있을 수 있을텐데, 예시를 예로 든다면 1일차에 일을 한다면 4일차의 값은 먼저 10이 될 것이다.
2일차를 본다. 2일차는 그럼 얼마의 값을 가질 수 있을까? 먼저 1일차에 0원이고, 1일 차에 1일차안에 완료될 수 있는 일을 하지 않았기 때문에 금액은 그대로 유지된다. 그런데 2일차에는 5일짜리 일을 할 수 있다. 따라서 d[7] = 20이된다.
여기가지 보면 d = [0,0,0,0,10,0,0,20,0]이 된다.
3일차를 본다. 3일차는 1일,2일차에 3일에 완료될 일을 아무것도 하지 않았기 때문에 값은 0이 된다. 3일차에는 1일짜리 일을 할 수 있게 된다. 즉, 3일차까지 아무것도 안하다가 3일차에 일을 하게 될 경우 4일차는 10의 값을 가진다. 기존에 있던 d[4]와 비교해봤을 때, 같은 값이기 때문에 아무것도 하지 않고 넘어간다.
4일차를 본다. 4일차는 1일에 일한 3일차짜리 일 또는, 혹은 3일차에 일한 1일차짜리 일로 인해 이미 10원의 돈을 번 것이 최대값이다. 여기서 4일차는 1일짜리 일을 또 할 수 있다. 따라서 d[5] = 10 + 20으로 30이 된다.
즉, 이런 식으로 방법이 진행되고 있다. 따라서 점화식을 살펴보면 다음과 같은 관계식을 가질 수 있다.
1. d[현재 시기+ 일에 필요한 시간] = d[현재 시기] + 해당 금액
2. d[현재 시기] = d[현재 시기 - 1]
1과 2중에 큰 값을 가지는 것이 d[현재 시간]이 된다. 이를 바탕으로 코드를 짜면 다음과 같다.
import sys
n = int(sys.stdin.readline().rstrip())
d = [0 for _ in range(n+2)]
day = [0]
value = [0]
for i in range(n):
a,b = map(int,sys.stdin.readline().split())
day.append(a)
value.append(b)
for i in range(1,n+1) :
if d[i] < d[i-1]:
d[i] = d[i-1]
if i + day[i] <= n+1 :
if d[i + day[i]] < d[i] + value[i] :
d[i + day[i]] = d[i] + value[i]
print(max(d))
'CS > BOJ' 카테고리의 다른 글
백준 2580 파이썬 코드 답안 (0) | 2021.06.24 |
---|---|
백준 1018 파이썬 답안 (0) | 2021.06.24 |
백준 2204 파이썬 문제 풀이 (0) | 2021.06.23 |
백준 1890 파이썬 문제 풀이 (0) | 2021.06.23 |
백준 8958 파이썬 코드 답안 (0) | 2021.03.22 |