iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0

問題

這邊一樣以 AtCoder Educational DP Contest 的類題來舉例,這題是 D - Knapsack 1,題意大概是有一個背包,裡面只能放重量 https://chart.googleapis.com/chart?cht=tx&chl=W 的東西,接下來有 https://chart.googleapis.com/chart?cht=tx&chl=n 個物品,每個物品都有價值與重量,現在要求可以放入背包物品的最大價值總和是多少,有個重點是物品皆不可以分割

解題思路

由於最多只能裝 https://chart.googleapis.com/chart?cht=tx&chl=W 且商品不可分割,所以不可以用 greedy 的方式來選擇商品,那試著思考看看,如果建一張 https://chart.googleapis.com/chart?cht=tx&chl=n%20%5Ctimes%20W 的表,枚舉重量由 https://chart.googleapis.com/chart?cht=tx&chl=1 ~ https://chart.googleapis.com/chart?cht=tx&chl=W 可以裝多少商品,且計算最高價值,然後歸納一個式子是https://chart.googleapis.com/chart?cht=tx&chl=%5Cbegin%7Bcases%7Ddp%5Bi%5D%5Bj%5D%20%3D%20max(dp%5Bi%20-%201%5D%5Bj%5D%2Cdp%5Bi%20-%201%5D%5Bj%20-%20w%5Bi%5D%5D%20%2B%20v%5Bi%5D)%3Bj%20-%20w%5Bi%5D%20%3E%3D%200%5C%5Cdp%5Bi%5D%5Bj%5D%20%3D%20dp%5Bi%20-%201%5D%5Bj%5D%3B%5Cend%7Bcases%7D,簡單來說是因為如果 j - w[i] >= 0 就代表裝的下此物品,所以就可以確認再裝物品下去會不會比較好或是直接沿用之前的裝填方式就可以了,只要不斷照著這步驟做就可以取得最高價值了

AC Code

#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    long long n,W;
    cin >> n >> W;
    vector<long long> w(n + 1),v(n + 1);
    for(int i = 1;i <= n;i++){
    	cin >> w[i] >> v[i];
    }
    vector<vector<long long>> dp(n + 1,vector<long long>(W + 1,0));
    for(int i = 1;i <= n;i++){
    	for(int j = 1;j <= W;j++){
    		if(j - w[i] >= 0){
    			dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]);
    		}else{
    			dp[i][j] = dp[i - 1][j];
    		}
    	}
    }
    cout << dp[n][W] << "\n";
    return 0;
}

時間複雜度

由於需要遍歷物品及枚舉各個重量,所以時間複雜度是https://chart.googleapis.com/chart?cht=tx&amp;chl=O(nW)

總結

今天的內容比較不好理解一些,不過背包問題可能會有變形的題目出現在比賽中,所以也是要好好理解並且練習思考


上一篇
Day28 - 動態規劃例題-不定型
下一篇
Day30 - 從競賽程式學習資料結構與演算法-最後總結
系列文
從競賽程式學習資料結構與演算法30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言