第5回 動的計画法
担当:laft
slides.com/procon2019/deck-7/fullscreen
KMC-ID:laft
あくまで一例ですが、下を参考に
新しく来た人だけで良さそう
実行時間制限:2sec
#include<bits/stdc++.h>
using namespace std;
long long fib(int n){
if(n==0) return 0;
if(n==1) return 1;
return fib(n-1) + fib(n-2);
}
int main(){
int n;
cin >> n;
cout << fib(n) << endl;
}
fib(10) = fib(9) + fib(8)
fib(10) = fib(9) + fib(8)
= (fib(8)+fib(7)) + (fib(7)+fib(6))
fib(10) = fib(9) + fib(8)
= (fib(8)+fib(7)) + (fib(7)+fib(6))
= ((fib(7)+fib(6))+(fib(6)+fib(5))
+ ((fib(6)+fib(5))+(fib(5)+fib(4))
fib(10) = fib(9) + fib(8)
= (fib(8)+fib(7)) + (fib(7)+fib(6))
= ((fib(7)+fib(6))+(fib(6)+fib(5))
+ ((fib(6)+fib(5))+(fib(5)+fib(4))
= (((fib(6)+fib(5))+(fib(5)+fib(4)))
+ ((fib(5)+fib(4))+(fib(4)+fib(3))))
+ (((fib(5)+fib(4))+(fib(4)+fib(3)))
+ ((fib(4)+fib(3))+(fib(3)+fib(2))))
fib(10) = fib(9) + fib(8)
= (fib(8)+fib(7)) + (fib(7)+fib(6))
= ((fib(7)+fib(6))+(fib(6)+fib(5))
+ ((fib(6)+fib(5))+(fib(5)+fib(4))
= (((fib(6)+fib(5))+(fib(5)+fib(4)))
+ ((fib(5)+fib(4))+(fib(4)+fib(3))))
+ (((fib(5)+fib(4))+(fib(4)+fib(3)))
+ ((fib(4)+fib(3))+(fib(3)+fib(2))))
= 以下同様に……
fib(10) = fib(9) + fib(8)
= (fib(8)+fib(7)) + (fib(7)+fib(6))
= ((fib(7)+fib(6))+(fib(6)+fib(5))
+ ((fib(6)+fib(5))+(fib(5)+fib(4))
= (((fib(6)+fib(5))+(fib(5)+fib(4)))
+ ((fib(5)+fib(4))+(fib(4)+fib(3))))
+ (((fib(5)+fib(4))+(fib(4)+fib(3)))
+ ((fib(4)+fib(3))+(fib(3)+fib(2))))
= 以下同様に……
fib(10) = fib(9) + fib(8)
= (fib(8)+fib(7)) + (fib(7)+fib(6))
= ((fib(7)+fib(6))+(fib(6)+fib(5))
+ ((fib(6)+fib(5))+(fib(5)+fib(4))
= (((fib(6)+fib(5))+(fib(5)+fib(4)))
+ ((fib(5)+fib(4))+(fib(4)+fib(3))))
+ (((fib(5)+fib(4))+(fib(4)+fib(3)))
+ ((fib(4)+fib(3))+(fib(3)+fib(2))))
= 以下同様に……
fib(6)は5回も呼び出されてる。
これは明らかに無駄!
#include<bits/stdc++.h>
using namespace std;
//mainなどの関数に入れずに作った変数をグローバル変数という。
//グローバル変数はどの関数からでも参照できる。
vector<long long> dp;
long long fib(int n){
if(dp[n]!=-1) return dp[n];
if(n==0) return 0;
if(n==1) return 1;
return dp[n] = fib(n-1) + fib(n-2);
}
int main(){
int n;
cin >> n;
//assignはvectorのサイズと中身を同時に設定する関数。
//これは初期化と全く同様に使える。[0,n]に-1をセット。
dp.assign(n+1,-1);
cout << fib(n) << endl;
}
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
ここでfib(2)の値が計算終了
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
これが解法1の時の再帰
ついでに探索順序の確認もしよう。
こんな感じ!
再帰してるので深さ優先になります。
次に解法2のイメージ
次に解法2のイメージ
次に解法2のイメージ
次に解法2のイメージ
次に解法2のイメージ
次に解法2のイメージ
ここでfib(2)の値をdp[2]に格納しておく
次に解法2のイメージ
dp[3]に格納
次に解法2のイメージ
dp[2]の値を使えばいいので下に行かなくて良い
次に解法2のイメージ
dp[2]の値を使えばいいので下に行かなくて良い
dp[4]に格納
次に解法2のイメージ
dp[3]を使う
次に解法2のイメージ
こんな風に、再帰回数を大幅に減らせる。
dp[3]を使う
fib(4)は既に求めているので再帰しなくていい。
fib(4)は既に求めているので再帰しなくていい。
fib(6)で増えた呼び出しは2つだけ
fib(4)は既に求めているので再帰しなくていい。
fib(6)で増えた呼び出しは2つだけ
fib(7)が増えても増える呼び出しは2つだけ
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
//[0,n]の配列dpを作る。
//dp[i]はフィボナッチ数列のi番目
vector<long long> dp(n+1);
dp[0] = 0;
dp[1] = 1;
for(int i=2;i<=n;++i){
dp[i] = dp[i-1] + dp[i-2];
}
cout << dp[n] << endl;
}
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
//[0,n]の配列dpを作る。
//dp[i]はフィボナッチ数列のi番目
vector<long long> dp(n+1,0);
dp[0] = 0;
dp[1] = 1;
for(int i=0;i<n;++i){
dp[i+1] += dp[i];
if(i+2<=n) dp[i+2] += dp[i];
}
cout << dp[n] << endl;
}
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
//[0,n]の配列dpを作る。
//dp[i]はフィボナッチ数列のi番目
vector<long long> dp(n+2,0); //こうすると後のif文を無くせる
dp[0] = 0;
dp[1] = 1;
for(int i=0;i<n;++i){
dp[i+1] += dp[i];
dp[i+2] += dp[i]; //if文消滅!!!!
}
cout << dp[n] << endl;
}
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 1 | 0 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 3 | 2 | 0 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 3 | 5 | 3 | 0 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 5 | 0 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 8 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 |
今の値を1つ次,2つ次の値に追加する。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
dp[n] | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 |
今の値を1つ次,2つ次の値に追加する。
愚直解とメモ化再帰
制約
n=4, W=7
具体例
1 | 2 | 3 | 4 | |
3 | 2 | 1 | 3 | |
5 | 3 | 4 | 4 |
この時、i=1,3,4を選ぶと価値の合計は13となり、最大となる。
全てについて取るか取らないか試してみる?
全てについて取るか取らないか試してみる?
int n,W;//main関数で入力しておく。
vector<int> w,v; //同上
//i番目の品物を選ぶ場合と選ばない場合の両方を試す。
//cwは選んだ物の重さの合計
int solve(int i,int cw){ //solve(0,W)で解を返す関数
//深さがnになるまで探索したら終了する。
if(i==n) return 0; //もう品物がないので0を返す。
int take;
//取る場合の値を再帰によって得る。取れる時は
if(cw+w[i]<W) take = v[i] + solve(i+1,cw+w[i]);
//取れない時は影響のない-1を代入。
else take = -1;
//取らない場合の値を再帰によって得る。
int untake = solve(i+1,cw);
//双方の大きい方を返す。
return max(take,untake);
}
int n,W;//main関数で入力しておく。
vector<int> w,v; //同上
vector<vector<int>> dp;//予め、全て-1でサイズn*(W+1)で初期化
//i番目の品物を選ぶ場合と選ばない場合の両方を試す。
//cwは選んだ物の重さの合計
int solve(int i,int cw){//solve(0,W)で解を返す。
if(i==n) return 0;
if(dp[i][cw]!=-1) return dp[i][cw];
int take = -1;
//取る場合の値を再帰によって得る。
if(cw+w[i]<W) take = solve(i+1,cw+w[i]);
//取らない場合の値を再帰によって得る。
int untake = solve(i+1,cw);
//双方の大きい方を返す。
return dp[i][cw] = max(take,untake);
}
int n,W;//main関数で入力しておく。
vector<int> w,v; //同上
//i番目の品物を選ぶ場合と選ばない場合の両方を試す。
//cwは選んだ物の重さの合計,cvは選んだ物の価値の合計
int solve(int i,int cw,int cv){ //solve(0,W,0)で解を返す関数
//深さがnになるまで探索したら終了する。
if(i==n){
if(cw<W) return cv;
else return -1; //選んだ物が条件を満たさない時-1を返す。
}
int take = solve(i+1,cw+w[i],cv+v[i]);
int untake = solve(i+1,cw,cv);
return max(take,untake);
}
こんな風に引数を3つの関数にしたり、引数のサイズを制限しない時、計算量的にメモ化再帰しても間に合わない。(そもそもしにくい)
もらうDP
n番目の品を取る時が最大になるとしたら
n番目の品を取らない時が最大になるとしたら
になりそう
n番目の品を取る時が最大になるとしたら
n番目の品を取らない時が最大になるとしたら
n番目の品を取る時は、それがそもそも無い時でかつ、その品の重さ分がそもそも無かった時の最大値にv[n]を足したものが答えになる。
n番目の品を取らない時は、それがそもそも無い時でかつ、今のWと同じ時の最大値が答えになる。
あっW-w[n]<0の時はもちろん
遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | |||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | |||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | |||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
重さがオーバーしてて取れない( 欄外 )
\(-2\)
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | |||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
重さがオーバーしてて取れない( 欄外 )
\(-2\)
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | ||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
重さがオーバーしてて取れない( 欄外 )
\(-2\)
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | ||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
重さがオーバーしてて取れない( 欄外 )
\(-1\)
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | ||||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
重さがオーバーしてて取れない( 欄外 )
\(-1\)
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | |||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
重さがオーバーしてて取れない( 欄外 )
\(-1\)
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | |||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | |||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+5
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | |||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+5
0+5と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | ||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+5
0+5と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | ||||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+5
0+5と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | |||
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+5
0+5と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | |||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | ||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | ||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | ||||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
0+3と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | |||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
0+3と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | |||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
0+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | ||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
0+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | ||||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
0+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | |||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
0+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | |||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
5+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | ||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
5+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | ||
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
5+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | |
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+3
5+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
5+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
5+3と5の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | |||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+4
0+4と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | 4 | ||||||
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
+4
0+4と0の大きい方を取る
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | 4 | 4 | 7 | 9 | 9 | 12 | 12 |
0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | 4 | 4 | 7 | 9 | 9 | 12 | 12 |
0 | 4 | 4 | 7 | 9 | 9 | 12 | 13 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
3 | 5 |
2 | 3 |
1 | 4 |
3 | 4 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 |
0 | 4 | 4 | 7 | 9 | 9 | 12 | 12 |
0 | 4 | 4 | 7 | 9 | 9 | 12 | 13 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 |
n
W
取る時、\((i-1,j-w[i])\)から遷移
取らない時、\((i-1,j)\)から遷移
答え!!
vector<int> w,v; //mainで入力
int given_dp(int n,int W){
vector<vector<int>> dp(n+1,vector<int>(W+1));
//初項の設定
for(int i=0;i<=n;++i) dp[i][0] = 0;
for(int i=0;i<=W;++i) dp[0][i] = 0;
//遷移の実行
for(int i=1;i<=n;++i){ //nについてのループ
for(int j=1;j<=W;++j){ //Wについてのループ
if(j-w[i-1]<0) dp[i][j] = dp[i-1][j];
else dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i-1]]+v[i-1]);
}
}
//答えは配列dpのここ
return dp[n][W];
}
配るDP
\(V_{n,W}\to V_{n+1,W+w[n+1]}\)
\(V_{n,W}\to V_{n+1,W}\)
\(V_{n+1,W+w[n+1]}\\=\max\{V_{n+1,W+w[n+1]},V_{n,W}+v[n+1]\}\)
\(V_{n+1,W}=\max\{V_{n+1,W},V_{n,W}\}\)
vector<int> w,v; //mainで入力
int dp_dist(int n,int W){
//最初は全部0で初期化
vector<vector<int>> dp(n+1,vector<int>(W+1,0));
for(int i=0;i<n;++i){
for(int j=0;j<=W;++j){
if(j+w[i]<=W){ //取れる時
dp[i+1][j+w[i]]
=max(dp[i+1][j+w[i]],dp[i][j]+v[i]);
}
//取らない時
dp[i+1][j] = max(dp[i+1][j],dp[i][j]);
}
}
return dp[n][W];
}