動態規劃
Dynamic Programming
定義
大問題->小問題
舉個栗子
栗子本栗想上一個十階的樓梯
他一次可以爬一階或兩階
請問總共有多少種走法?
以邏輯方面來看
十階
九階+1
八階+2
(八階+1)+1
(七階+2)+1
(七階+1)+2
(六階+2)+2
#include<bits/stdc++.h>
using namespace std;
int climb(int n)
{
if(n==1)
return 1;
if(n==2)
return 2;
else
return climb(n-1)+climb(n-2);
}
int main()
{
int n;
cin>>n;
cout<<climb(n);
}
再舉個栗子
栗子爬完樓梯很累所以他要來找走到目的地最短路徑
從左上角開始 他每次只能向右走或向下走
每格數字代表行經該格的路徑長
請問走到右下角累計消耗的最短路徑是多少?
0
7
8
9
1
2
5
1
1
4
0
10
動腦思考一下
因為只能向右或向下走
所以一個格子的前一步一定是來自左方或上方
故根據邏輯推理得知
到達一個格子累計最短的路徑
是該格所代表路徑長及min(左方或上方)之和
0
7
8
9
1
2
5
1
1
4
0
10
0
7
8
9
1
2
5
1
1
4
0
10
0
7
15
9
1
2
5
1
1
4
0
10
0
7
15
24
1
2
5
1
1
4
0
10
0
7
15
24
1
2
5
1
1
4
0
10
0
7
15
24
1
3
5
1
1
4
0
10
0
7
15
24
1
3
5
1
1
4
0
10
要找min(左方或上方)
由表可知1比較小 故選1
0
7
15
24
1
3
6
1
1
4
0
10
0
7
15
24
1
3
6
1
1
4
0
10
0
7
15
24
1
3
6
1
1
7
0
10
0
7
15
24
1
3
6
1
1
7
0
10
0
7
15
24
1
3
6
7
1
7
0
10
0
7
15
24
1
3
6
7
1
7
0
10
0
7
15
24
1
3
6
7
1
7
0
17
0
7
15
24
1
3
6
7
1
7
0
17
0
7
15
24
1
3
6
7
8
7
0
17
0
7
15
24
1
3
6
7
8
7
0
17
0
7
15
24
1
3
6
7
8
7
8
17
故可得最短路徑為8
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int path[100][100]={0};
for(int i=0;i<n;i++)
{
for(int t=0;t<m;t++)
cin>>path[i][t];//讀入資料
}
for(int i=1;i<n;i++)
path[i][0]+=path[i-1][0];//累計最左直排
for(int t=1;t<m;t++)
path[0][t]+=path[0][t-1];//累計最上橫排
for(int i=1;i<n;i++)
{
for(int t=1;t<m;t++)
path[i][t]+=min(path[i-1][t],path[i][t-1]);
//取該格左方和上方最小的那個
}
cout<<path[n-1][m-1]<<endl;
}
最後一個栗子
背包問題
現在栗子要載運一些貨品,但他體力有限。每一項貨品k都有一個已知的重量wei[k],以及載運的利潤val[k],希望選出其中的若干項,其重量總和不超過100,使得利潤最大。
(翻譯:在重量100內最大利潤是多少?)
動腦思考一下
背包裡可以放入比他小的背包
例如容量為10的背包可以放進容量為4和6的背包
以此類推容量為4的背包也可以放入容量為1和3的背包
然後空間盡量不要浪費 最大化利用栗子的體力:D
背包問題
翻譯:在重量100內最大利潤是多少?
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
wei=重量
val=價值
全部都先除以10比較好講
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
cin
wei=3
val=6
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
這兩個容量只有1和2
放不下3
k[3]=6
代表容量為3的背包可以裝下價值6
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
cin
wei=2
val=5
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
5 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
思考:
如果現在新進來的價值配上一個小背包
利潤會變大嗎?
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
5 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
新進來的重量是2 價值是5
若放進重量4的背包會搭配重量2 那他的總價值=新進來的價值5+重量2背包的價值5=5+5=10
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
5 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
新進來的重量是2 價值是5
若放進重量4的背包會搭配重量2 那他的總價值=新進來的價值5+重量2背包的價值5=5+5=10
你沒有那麼多貨品!!!
價值2已經放進去容量為2的背包一次了
再放進去4一次就是放兩次了
你只有一個貨品!
解方:從後面開始放入 避免重複放同一個貨品
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
cin
wei=2
val=5
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
新進來的重量是2 價值是5
若放進重量10的背包會搭配重量8 那他的總價值=新進來的價值5+重量8背包的價值6 =5+6=11
又11>6 故取11
背包問題
k[1] | k[2] | k[3] | k[4] | k[5] | k[6] | k[7] | k[8] | k[9] | k[10] |
---|---|---|---|---|---|---|---|---|---|
6 | 6 | 11 | 11 | 11 | 11 | 11 | 11 |
因為背包1和2加上新的價值後不大於6
故不變
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int wei[110]={0},val[10000]={0};
int k[110]={0};
for(int i=0;i<n;i++)
cin>>wei[i]>>val[i];
for(int i=0;i<n;i++)
{
for(int t=100;t>=wei[i];t--)
{//從後面開始放入
if(k[t-wei[i]]+val[i]>k[t])
k[t]=k[t-wei[i]]+val[i];
//判定放入後價值是否更高
}
}
cout<<k[100]<<endl;
}
}
TRY TRY SEE
NO KAHOOT!
DP
By ㄌㄌ
DP
- 104