動態規劃:洛谷 P1280 尼克的任務
阿新 • • 發佈:2022-04-12
洛谷 P1280 尼克的任務
這是洛谷的一題綠題,考的是動態規劃。我們先想狀態轉移方程,這是個線性的dp,那麼可以考慮每一個時間,dp[]就代表0-此時間內的最大閒暇時間,但發現最大閒暇時間,前面的選擇會對後面的選擇產生影響,有後效性,所以不妨倒著來,從最後一個時間一直遞推到第一個,後面選擇的任務對前面任務的選擇並不會產生影響的。所以我們遍歷每一個時間,狀態轉移方程:如果這個點沒有work,那麼dp[i]=dp[i+1]+1就是上一個空閒時間+1,如果有,就開一個迴圈,遍歷這個時間點的所有工作worktime[j],dp[i]=max(dp[i+worktime[j]]);
上程式碼:
1 //洛谷 P1280 尼克的任務 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int dp[10005], num[10005], n, k;//num陣列存的是這個時間點有幾個任務開始 7 //dp陣列存的是從n分鐘到這個第i時間的最長休閒時間 8 struct worktime 9 { 10 int b; 11 int l; 12 }work[10005];//存放工作開始和持續時間的結構體 13 boolcmp(worktime a, worktime c) 14 { 15 return a.b > c.b;//從大到小排序一下,因為是逆向 從時間大到時間小去DP 16 } 17 int main() 18 { 19 20 cin >> n >> k; 21 for (int i = 1; i <= k; ++i) 22 { 23 cin >> work[i].b >> work[i].l; 24 num[work[i].b]++; 25 } 26 sort(work + 1, work + 1 + k, cmp);//從小到大排序一下 27 int x = 1;//這是一個標誌,因為下面有任務就要遍歷一下這個時間點的所有work,尋找最優解 28 //我們乾脆引入一個x就是work裡面的下標,因為work已經從大到小排序過,所以我們每次只要看work[x],x++,這樣每次判斷的work[x]會剛好,可以自己舉例驗證 29 for (int i = n; i >= 1; --i) 30 { 31 if (!num[i])//如果這個時間沒有work 那麼他的休閒時間就等於前一個休閒時間+1分鐘 32 dp[i] = dp[i + 1] + 1; 33 else//否則就開始迴圈 找最優解 34 { 35 for (int j = 1; j <= num[i]; ++j)//迴圈num[i]次 36 { 37 dp[i] = max(dp[i], dp[i + work[x].l]); 38 x++; 39 //如果只有一個任務,那麼dp[i]一定等於0,這樣也一定會接這個任務, 40 //保證了符合題目,有一個任務必須做,有兩個以上就max比較,因為i到i+work[x].l的時間在做任務 41 //所以i時間的最大休息時間等於i+workx.l; 42 //記得++x 43 } 44 } 45 46 } 47 48 cout << dp[1];//dp[1]就是最終答案 49 return 0; 50 51 }
完美通過:
時間複雜度也只是o(n+k),順利通過。