도둑이 4파운드의 짐을 넣을 수 있는 배낭에 값나가는 물건을 최대한 많이 훔치려 한다.
훔칠 수 있는 물건은 3종류
훔친 물건의 총 가치를 최대한으로 하려면 어떤 물건들을 훔쳐야 하는가?
모든 물건들의 조합과 총 가치를 모두 구한 다음, 가장 가치 높은 경우를 선택
단점 : 너무 느리다. O(2의n제곱)
. 물건이 하나 추가될 때마다 경우의 수가 2배가 된다. 2, 4, 8, 16, 32...
8장에서는 이 문제의 근사해를 구해 보았다(탐욕 알고리즘으로).
그렇다면 최적해는 어떻게 구할까?
: 어려운 문제를 여러 개의 하위 문제로 쪼개고, 하위 문제들을 먼저 해결하는 방법.
위의 배낭 채우기 문제에서는 - 더 작은 배낭(1파운드 배낭, 2파운드 배낭..)에 대한 문제를 풀고 이를 이용해 원래의 문제를 푼다.
모든 동적 프로그래밍 알고리즘은 격자 grid에서 시작한다.
격자의 각 칸에는 최적화하고자 하는 값을 적는다.
격자의 칸 = 원래 문제에 대한 하위 문제이다.
격자를 모두 채우면 문제에 대한 답이 나온다.
동적 프로그래밍의 해답을 계산해 주는 쉬운 공식 같은 것은 없다.
--- | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
기타 | |||||
스테레오 | |||||
노트북 |
이 행에서는 기타만 넣을 수 있다. 결정할 수 있는 것은 기타를 넣을지 넣지 않을지 뿐이다.
--- | 1 | 2 | 3 | 4 |
---|---|---|---|---|
G(기타) | 1500(G) | 1500(G) | 1500(G) | 1500(G) |
S(스테레오) | ||||
L(노트북) |
--- | 1 | 2 | 3 | 4 |
---|---|---|---|---|
G(기타) | 1500(G) | 1500(G) | 1500(G) | 1500(G) |
S(스테레오) | 1500(G) | 1500(G) | 1500(G) | 3000(S) |
L(노트북) |
--- | 1 | 2 | 3 | 4 |
---|---|---|---|---|
G(기타) | 1500(G) | 1500(G) | 1500(G) | 1500(G) |
S(스테레오) | 1500(G) | 1500(G) | 1500(G) | 3000(S) |
L(노트북) | 1500(G) | 1500(G) | 2000(L) | 3500(L+G) |
마지막 칸의 값 구하기 - 아래 둘을 비교한다.
: 작은 배낭(1,2 파운드)에 대한 최대 가치를 계산하면, 더 큰 배낭에 공간이 남게 되었을 때 작은 배낭에 대한 답을 사용하여 빈 공간의 가치가 최대가 되는 값을 찾을 수 있기 때문이다.
칸[i][j]
의 최대값 (i
= 행, j
= 열)
지금까지 구한 칸[i-1][j]
의 값 중에서 가장 최대값 (=세로줄 상의 최대값)
또는 현재 물건의 가치 + 남은 공간의 가치
[i-1][j-물건의 무게]
1 | 2 | 3 | 4 | |
---|---|---|---|---|
G(기타) | 1500(G) | 1500(G) | 1500(G) | 1500(G) |
S(스테레오) | 1500(G) | 1500(G) | 1500(G) | 3000(S) |
L(노트북) | 1500(G) | 1500(G) | 2000(L) | 3500(L+G) |
I(아이폰) | 2000(I) | 3500(I+G) | 3500(I+G) | 4000(I+L) |
행의 순서가 바뀌어도 답은 바뀌지 않는다.
배낭 채우기의 경우는 아무런 차이가 없지만, 다른 문제에서는 영향이 있을 수 있다.
만약 무게가 0.5파운드인 목걸이가 훔칠 수 있는 목록에 추가된다면?
배낭의 종류를 1파운드 단위에서 0.5파운드 단위로 세분화해야 한다.
--- | 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4 |
---|---|---|---|---|---|---|---|---|
전체를 훔치는 것이 아니라 일부만 훔칠 수는 없는가?
런던으로 휴가를 떠나는데, 이틀 동안 머물면서 가능한 많은 관광지를 돌고 싶다.
각 관광지마다 걸리는 시간과 보고 싶은 정도를 정하고 어떻게 코스를 짤지 정하는 문제.
= 배낭 채우기 문제와 같다.
위의 여행 일정 최적화 문제에서, 관광지로 파리 여행도 추가하려 한다.
런던-파리는 반나절이 걸린다. 런던-파리를 오가는 경우 걸리는 시간에 1/2일을 더해야 한다.
두 개 이상의 물건을 훔친다면 하위 배낭이 두 개 이상일 수도 있다. (하위 배낭이 그 안에 다시 하위 배낭을 갖는 식으로)
배낭을 완전히 채우지 않더라도 그 경우가 최대 가치라면 그럴 수 있다.
사용자가 검색어를 실수로 잘못 입력했을 때, 대신 비슷한 단어들을 찾아 줌
실수로 입력한 검색어와 가장 유사한 단어를 후보로 보여주어야 한다. - 최장 공통 부분 문자열 또는 최장 공통 부분열을 구한다.
--- | h | i | s | h |
---|---|---|---|---|
f | 0 | 0 | 0 | 0 |
i | 0 | 1 | 0 | 0 |
s | 0 | 0 | 2 | 0 |
h | 1 | 0 | 0 | 3 |
if wordA[i] == wordB[j]:
cell[i][j] = cell[i-1][j-1] + 1
else:
cell[i][j] = 0
❗ 이 문제의 경우 마지막 칸이 최종 답이 아니다. 답은 격자 전체에서 가장 큰 숫자이다. ( = 3, 즉 세 글자가 공통이다.)
fosh라고 실수로 입력했을 때, fish를 검색하려던 것일까? fort를 검색하려던 것일까?
--- | f | o | s | h |
---|---|---|---|---|
f | 1 | 1 | 1 | 1 |
i | 1 | 1 | 1 | 1 |
s | 1 | 1 | 2 | 2 |
h | 1 | 1 | 2 | 3 |
[0][0]
의 경우) 만약 두 글자가 같으면 1이고, 다르면 0이다.if wordA[i] == wordB[j]:
cell[i][j] == cell[i-1][j-1] + 1
else:
cell[i][j] = max(cell[i-1][j], cell[i][j-1])