尼克的任务——线性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

 

posted @ 2022-04-03 15:33  wellerency  阅读(27)  评论(0编辑  收藏  举报