動態規劃 洛谷P1616 瘋狂的採藥
阿新 • • 發佈:2022-03-31
動態規劃 洛谷P1616 瘋狂的採藥
同樣也是洛谷的動態規劃一個普及-的題目,接下來分享一下我做題程式碼
看到題目,沒很認真的看資料大小,我就提交了我的程式碼:
1 //動態規劃 洛谷P1616 瘋狂的採藥 2 #include<iostream> 3 #include<cmath> 4 using namespace std; 5 int value[10005];//價值陣列 6 int times[10005];//時間陣列 7 int dp[10000003];//t的範圍1e7 8 int main() 9 { 10 int m, t;//m是數目,t是時間 11 cin >> t >> m;12 for (int i = 1; i <= m; ++i) 13 { 14 cin >> times[i] >> value[i];//輸入資料 15 } 16 //從小遍歷到大進行規劃 因為這題可以選無數個一樣的 17 for (int i = 1; i <= t; ++i) 18 { 19 for (int j = 1; j <= m; ++j)//對每一種草藥進行遍歷 20 { 21 if (i >= times[j])//前提是時間大於採摘所需要的時間才能考慮22 { 23 dp[i] = max(dp[i], dp[i - times[j]] + value[j]); 24 } 25 } 26 } 27 cout << dp[t]; 28 return 0; 29 30 }
測試了幾個測試用例,過了 ,於是乎,我就自信滿滿的提交了!
但是!
仔細觀察資料大小,經典的沒開long long
於是改正:
1 //動態規劃 洛谷P1616 瘋狂的採藥 2 #include<iostream> 3#include<cmath> 4 using namespace std; 5 int value[10005];//價值陣列 6 int times[10005];//時間陣列 7 long long dp[10000003];//t的範圍1e7 long long !!!! 8 int main() 9 { 10 int m, t;//m是數目,t是時間 11 cin >> t >> m; 12 for (int i = 1; i <= m; ++i) 13 { 14 cin >> times[i] >> value[i];//輸入資料 15 } 16 //從小遍歷到大進行規劃 因為這題可以選無數個一樣的 17 for (int i = 1; i <= t; ++i) 18 { 19 for (int j = 1; j <= m; ++j)//對每一種草藥進行遍歷 20 { 21 if (i >= times[j])//前提是時間大於採摘所需要的時間才能考慮 22 { 23 dp[i] = max(dp[i], dp[i - times[j]] + value[j]); 24 } 25 } 26 } 27 cout << dp[t]; 28 return 0; 29 30 }
然後!
結束啦!
總結歸納一下: 這題和P1048 [NOIP2005 普及組] 採藥 非常像,只是資料加強了些,而且我們對比可以發現,還有一個區別就是每個藥可以採摘無數次。
於是我們歸納出一個模板,像只能採摘一次,也就是選擇一次的揹包問題,我們用採摘時間time值來做外層迴圈,反正每次只能選擇一次,也就是拿每種草藥的時間來遍歷.
//也就是 for(int i=1;i<=m;++i) { for(int j=x(揹包的最大容量),j>=time[i],--j) { dp[j]=max(dp[j],dp[j-time[i]]+value[i]); } }
但是像這一題,每次可以選擇無數次,我們外層迴圈就只能用時間了,有點像選硬幣湊錢問題。從1一直遍歷到最大的time。內層去遍歷每一種草藥,因為可以採摘多次,得出我們的模板:
for (int i = 1; i <= t(最大時間); ++i)從小到大隊每一個時間進行dp 算出每一個時間的最優解 { for (int j = 1; j <= m(可供選擇的種類數); ++j)//對每一種草藥進行遍歷 { if (i >= times[j])//前提是時間大於採摘所需要的時間才能考慮 { dp[i] = max(dp[i], dp[i - times[j]] + value[j]); } } }