dp의 시작은 중복되는 부분이 있냐, 그리고 큰문제를 작은 단위로 나눌수있느냐? 로 시작할 수 있다.
하지만, 이부분만으로는 dp라고하기 어렵다. 중복되는 계산 결과를 저장하지않으면, 전에 했던 과정들을 다시 시작해야되기 때문에, 이미 했던 과정을 반복하지않기위해 저장하는 메모이제이션(Memoization
) 이 꼭 들어가줘야한다.
단순히 DP문제라 하면, 누가봐도 반복이 눈에 보이는 문제이며, 이후 작은 단위의 선택지가 보이는 경우가 대부분이다.
이렇게 직관적인 DP문제들을 반복되는 구간을 명시적으로 보여준다.
하지만, knapsack(배낭) 문제의 경우 반복적인 부분이 겉으로 드러나있지 않기때문에 내가 그 반복적인 부분
을 찾아야 된다는것이다.
결국 중요한 부분은 선택지가 배낭에 물건을 "담는다" 와 "안담는다" 라는 점에 초점을 맞춰야한다는 것은 OK 알겠다. 하지만 DP배열은 어떻게 만들어야할까?
무게의 제한이라는 조건이 있기때문에 어려워진것이다.
그럼 무게제한이 없다고 생각하면 어떻게 될까?
무게 제한이 없다면 사실 배낭에 모든 물건을 다 넣으면 되지만, 이해를 위해 담을 경우와 담지않을 경우로 나눠보자
무게 | 가치 |
---|---|
1KG | 20 |
2KG | 10 |
3KG | 40 |
4kG | 30 |
0~4
개 가 된다. 이걸 N이라 하자W
라 하자 그럼 0~10
이 된다. 가치
를 표현해보고자한다.그럼 이걸 표로 그리면, 아래처럼 된다.
N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | |||||||||||
1 | |||||||||||
2 | |||||||||||
3 | |||||||||||
4 |
N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||||||
2 | 0 | ||||||||||
3 | 0 | ||||||||||
4 | 0 |
N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | ||||||||||
3 | 0 | ||||||||||
4 | 0 |
1KG
물건의 가치는 20
이고, 2KG
물건의 가치는 10
이다.1
이고 무게가2
일때 나올수 있는 최고의 가치는 Math.max(20,10) = 20
이 나오게 만드는 것이다. 이제부터는 2개를 넣을 수 있다.
2개의 값을 물론 처음부터 계산해도 되지만, 기존에 계산한 것들을 활용하여 넣어보자.(중요!!!)
현재 가능한 무게 - 담을 무게
) < 0 dp[2][1] = dp[1][1]
, dp[2][2] = dp[1][2]
먼저 위에 식이 이해가 되야한다. 추가로 담을 수 없으니, 기존의 최고의 가치값으로 넣어준다는 것! 이것이 담는다 안담는다 선택지중에
"안담는다"
이다!
N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | ||||||||
3 | 0 | ||||||||||
4 | 0 |
N=2,W=3
의 경우를 봐보자 N=1 W=1
에서 + 2KG
를 추가한 경우N=1 W=2
에서 + 1KG
를 추가한 경우for(int i=1; i<=n; i++){
int weight = jewels[i].weight;
int value = jewels[i].value;
for(int j=0; j<=w; j++){
if(j >= weight) //추가로 담는 물건의 무게가 넘어가지 않는다면,
dp[i][j] = Math.max(dp[i-1][k]+ value[j-k], dp[i-1][j])
else{ //무게가 넘어가기때문에 이전의 최대값을 넣는다.
dp[i][j] = dp[i-1][j];
}
}
}
N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | 30 | 30 | ||||||
3 | 0 | ||||||||||
4 | 0 |
N=2, W=4
의 경우에도 (1KG,2KG)가 가능하다. W=10
까지 똑같이 적용하면 아래와 같이 된다.N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 |
3 | 0 | ||||||||||
4 | 0 |
N=3 W=3
일 경우 조금 달라진다. N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 |
3 | 0 | 20 | 20 | 40 | |||||||
4 | 0 |
W=4
일경우엔60
이 제일 큰 가치기에 값이 들어가고 W=5
일경우엔50
도 가능하나60
여전히 이값이 큰값이기에 들어간다. W=6
이후엔 3가지가 담을 수 있기에 70
으로 값이 들어간다. N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 |
3 | 0 | 20 | 20 | 40 | 60 | 60 | 70 | 70 | 70 | 70 | 70 |
4 | 0 |
N\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | 30 | 30 | 30 | 30 | 30 | 30 | 30 | 30 |
3 | 0 | 20 | 20 | 40 | 60 | 60 | 70 | 70 | 70 | 70 | 70 |
4 | 0 | 20 | 20 | 40 | 60 | 60 | 70 | 70 | 90 | 90 | 100 |
예를 들어 무게 제한이 5KG라고 해보자
배열의 크기
밖에 없다. N\W | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 20 | 20 | 20 | 20 | 20 |
2 | 0 | 20 | 20 | 30 | 30 | 30 |
3 | 0 | 20 | 20 | 40 | 60 | 60 |
4 | 0 | 20 | 20 | 40 | 60 | 60 |
아는 만큼 보이는게 맞는 것 같다. 나처럼 dp배열부터 이해가 안가시는 분들이 직접 파헤쳐보시면서 이해가 되셨으면 좋겠으며, 저처럼 한 걸음 더 나아간 느낌이 들었으면 한다.