1. 程式人生 > 其它 >尼克的任務——線性dp

尼克的任務——線性dp

P1280 尼克的任務 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

一道線性dp的基礎題。但是狀態方程自己想複雜了。剛開始是想用二維陣列表示,選擇i項工作後時間到j的總工作時長最小是多少,然後用總時間減它。很麻煩,而且不會寫.。。。然後看了題解,發現只需要一維陣列即可。狀態表示是從第i分起開始工作的最大摸魚時間。

 

問題:為什麼狀態方程不是從第1分鐘開始到第i分鐘結束的最大摸魚時間呢?

  因為這樣思考量太大了,還要考慮前幾項工作的最終時長什麼的。所以正難則反,我們的狀態方程設為i分鐘是起點。

 

狀態計算:

  1.如果i時刻沒有工作剛開始,那麼f[i]=f[i+1]+1 (摸魚一分鐘)

  2.如果i時刻有工作要剛開始,那麼就在所有i時刻開始的工作中遍歷,求最大的摸魚時長。

    f[i]=max(f[i],f[i+num[i][j])

  答案所求即為f [ 1 ]

 

小技巧:用vector記錄每項工作開始時間對應的結束時間,沒必要記錄每項工作的序號。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e4+100;
 4 vector<int>num[N];
 5 int n,k,p,t,f[N];
 6 
 7 int main()
 8 {
 9     scanf("
%d%d",&n,&k); 10 for(int i=1;i<=k;i++) 11 { 12 scanf("%d%d",&p,&t); 13 num[p].push_back(t); 14 } 15 16 for(int i=n;i;i--) 17 { 18 if(num[i].empty())f[i]=f[i+1]+1; 19 else 20 { 21 for(int j=0;j<num[i].size();j++)
22 f[i]=max(f[i],f[i+num[i][j]]); 23 } 24 } 25 26 printf("%d\n",f[1]); 27 28 29 30 return 0; 31 }
View Code