尼克的任务——线性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 @   wellerency  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示