【题解】 P1280 尼克的任务

本文介绍了一道动态规划题目,旨在找到给定工作安排中从第1天到第n天的最大空闲时间。通过定义dp数组,状态转移方程以及按结束时间降序排列工作,从后往前枚举,最终求得最大空闲时间。文章详细解释了状态转移过程,并给出了完整的C++代码实现。
摘要由CSDN通过智能技术生成

搞清楚了就很简单的dp题!

思路

设dp[i]表示i ~ n的最大空闲时间
状态转移方程:
(空闲) dp[i] = dp[i + 1] + 1;
(有工作)dp[i] = max(dp[i], dp[i + s[num++].time);
(在 i 时刻的开始工作的此工作需要持续的时间为 s[num++].time)
所以我们需要一个结构体来存储开始的时间和工作持续的时间
struct Node
{
  int begin, time;
}s[N];
因为后面的开始时间会影响前面的休息时间,有多种可能的选择,所以我们不从前面枚举,而是从最后往前面枚举休息时间。
为了让开始时间放到一起,所以我们要排序一下,又因为我们要从最后开始枚举起,所以我们要按降序来排序

  bool cmp (Node x, Node y)
  {
    return x.begin > y.begin;
  }
  
  sort(s + 1, s + k + 1, cmp);
哼哼,紧接着就开始举例子了!(因为语言根本不会说)
我们看排序后的样例!
begintime
115
85
81
411
12
16
这就是排好序的开始时间和工作要持续的时间。然后我们从n ~ 1开始枚举每个 i 的空闲时间,分两个状态转移方程(在上面)
dp      n

1       15 dp[15] = dp[15 + 1] + 1 = dp[16] + 1 = 0 + 1 = 1;
	     (n = 15的时候没有需要开始工作的时间, 所以空闲时间直接加1)
    
2       14  dp[14] = dp[14 + 1] + 1;
3       13  dp[13] = dp[13 + 1] + 1;
4       12  dp[12] = dp[12 + 1] + 1;

0       11  dp[11] = max (dp[11 + 5], dp[11]); 
            dp[16] = dp[11 + s[11].time] <-(s[11].time == 5)
            dp[11] = dp[16] = 0;
       	 (n = 11有工作,持续时间为 5 ,所以在nz在11~15休息时间为0)

1       10  dp[10] = dp[10 + 1] + 1;
2       9   dp[9] = dp[9 + 1] + 1;

3       8   (j = 1)dp[8] = max (dp[8 + 5], dp[8]); 
            (j = 2)dp[8] = max (dp[8 + 1], dp[8]);
            dp[8] = max((j = 1)dp[8], (j = 2)dp[8]);
            dp[8] = (j = 1)dp[8] = dp[13] = 3;
         (n = 8有两份工作,所以比较这两份工作哪份休息时间多就选哪份)
           
4       7  dp[7] = dp[7 + 1] + 1;
5       6  dp[6] = dp[6 + 1] + 1;
6       5  dp[5] = dp[5 + 1] + 1;
1       4  dp[4] = max (dp[4 + 11], dp[4]) = dp[15] = 1; 
2       3  dp[3] = dp[3 + 1] + 1;
3       2  dp[2] = dp[2 + 1] + 1;
4       1  dp[1] = dp[1 + 1] + 1;
当当~就这样dp[1]就是1 - n 的最大空闲时间啦! 正解得出!
下面就直接放代码咯~
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e5 + 50;
int n, k, dp[N], num[N];

struct Node
{
  int begin, time;
  friend bool operator < (Node x, Node y)
  {
    return x.begin > y.begin;
  }
}s[N];

int main()
{
  cin >> n >> k;
  for(int i = 1; i <= k; i++)
  {
    cin >> s[i].begin >> s[i].time;
    //存当前的开始时间有几个数(同时刻工作数量)!
    num[s[i].begin]++;
  }
  sort(s + 1, s + k + 1);

  int p = 1;
  // 设f[i]表示i ~ n的最大空闲时间
  for(int i = n; i >= 1; i--)
  {
    //当前时间没有工作数
    if(num[i] == 0)
    {
      //i 到 n 时的空闲时间
      dp[i] = dp[i + 1] + 1;
    }
    else
    {
      for(int j = 1; j <= num[i]; j++)
      {
        //当前起始位置的j个数相比哪个空闲时间多 dp[i]就取哪个
        dp[i] = max (dp[i + s[p++].time], dp[i]);
      }
    }
  }
  cout << dp[1] << endl;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值