圖解轉載 原創代碼適合新手入門

說明

假設有一個揹包的負重最多可達8公斤,而希望在揹包中裝入負重範圍內可得之總價物品,假設是水果好了,水果的編號、單價與重量如下所示:

0 李子 4KG NT$4500
1 蘋果 5KG NT$5700
2 橘子 2KG NT$2250
3 草莓 1KG NT$1100
4 甜瓜 6KG NT$6700

解法

揹包問題是關於最佳化的問題,要解最佳化問題可以使用“動態規劃”(Dynamic programming),從空集合開始,每增加一個元素就先求出該階段的最佳解,直到所有的元素加入至集合中,最後得到的就是最佳解。


以揹包問題爲例,我們使用兩個陣列value與item,value表示目前的最佳解所得之總價,item表示最後一個放至揹包的水果,假設有負重量 1~8的揹包8個,並對每個揹包求其最佳解。


逐步將水果放入揹包中,並求該階段的最佳解:

  • 放入李子
揹包負重 1 2 3 4 5 6 7 8
value 4500 4500 4500 4500 9000
item


  • 放入蘋果
揹包負重 1 2 3 4 5 6 7 8
value 4500 5700 5700 5700 9000
item 1 1 1
  • 放入橘子
揹包負重 1 2 3 4 5 6 7 8
value 2250 2250 4500 5700 6750 7950 9000
item 2 2 1 2 2


  • 放入草莓
揹包負重 1 2 3 4 5 6 7 8
value 1100 2250 3350 4500 5700 6800 7950 9050
item 3 2 3 1 3 2 3


  • 放入甜瓜
揹包負重 1 2 3 4 5 6 7 8
value 1100 2250 3350 4500 5700 6800 7950 9050
item 3 2 3 1 3 2 3


由最後一個表格,可以得知在揹包負重8公斤時,最多可以裝入9050元的水果,而最後一個裝入的水果是3號,也就是草莓,裝入了草莓,揹包只能再放入7公斤(8-1)的水果,所以必須看揹包負重7公斤時的最佳解,最後一個放入的是2號,也就是橘子,現在揹包剩下負重量5公斤(7-2),所以看負重5公斤的最佳解,最後放入的是1號,也就是蘋果,此時揹包負重量剩下0公斤(5-5),無法再放入水果,所以求出最佳解爲放入草莓、橘子與蘋果,而總價爲9050元。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e3;
int v, n;
int value[N],w[N];
int dp[N][N];
int main()
{
    cin >> n >> v;//n個物品 v的容量
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= n; i++)
        cin >>w[i] >>value[i];



    for (int i = 1; i <= n; i++)
        for (int j = v; j >= w[i]; j--)
            dp[i][j] =max(dp[i-1][j], dp[i - 1][j - w[i]] + value[i]); //類比與講解中的蘋果取代李子那一步/
      cout << dp[n][v] << endl;



//一維數組版
// 注意改成dp[N];  還有必須要倒着循環第二層循環,防止出現有光物品多次選取
//  for (int i = 1; i <= n; i++)
//      for (int j = v; j >= w[i]; j--)
//        dp[j] =max(dp[j], dp[j - w[i]] + value[i]);  //壓縮成一維的,應爲我們發現當前狀態之和現在和上一步有關係。還可以用滾動數組來優化但不如這樣
//  cout << dp[v] << endl;



//滾動數組版
// int dp[2][N]
//    int pre,now;
//    pre=0,now=1;
//    for (int i = 1; i <= n; i++)
//    {
//        for (int j = v; j >= w[i]; j--)
//        {
//            dp[now][j] =max(dp[pre][j], dp[pre][j - w[i]] + value[i]);
//
//        }
//        swap(now,pre);
//    }
//    cout << dp[now][v] << endl;



//正向遞推版
// for(int i=1;i<=n;i++)
//   for(int j=w[i];j<=v;j++)
//    dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+value[i]);
//    cout<<dp[n][v]<<endl;
    return 0;
}
//測試數據
//5 8
//4 4500
//5 5700
//2 2250
//1 1100
//6 6700
//ans 9050

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章