[每日算法]尼克的任务


题目描述

尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。

尼克的一个工作日为 n 分钟,从第 1 分钟开始到第 n 分钟结束。当尼克到达单位后他就开始干活,公司一共有 k 个任务需要完成。如果在同一时刻有多个任务需要完成,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去完成,假如某些任务开始时刻尼克正在工作,则这些任务也由尼克的同事完成。如果某任务于第 p 分钟开始,持续时间为 t 分钟,则该任务将在第 (p+t−1) 分钟结束。

写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间。

输入格式

输入数据第一行含两个用空格隔开的整数 nk

接下来共有 k 行,每一行有两个用空格隔开的整数 pt,表示该任务从第 p 分钟开始,持续时间为 t 分钟。

输出格式

输出文件仅一行,包含一个整数,表示尼克可能获得的最大空暇时间。

输入输出样例

样例#1 输出#1
15 6
1 2
1 6
4 11
8 5
8 1
11 5
4

说明/提示

  • 对于 100% 的数据,保证 1≤n≤10^4,1≤k≤10^4,1≤p≤n,1≤p+t-1≤n。

题解

这个题是一个线性的动态规划问题,第i时刻的最大空闲时间是和后面i+选择任务的持续时间的时刻有关系的,如果正着找是不那么容易的,但是如果倒着查找就会容易很多,可以得到相应的状态转移方程:

如果本时刻无任务时,那么这个时刻的空闲时间为上一个时刻的最大空闲时间+1:f[i]=f[i+1]+1

如果本时刻有任务,begins表示这个时刻的任务的持续时间,那么状态转移方程为:fx[i] = max(fx[i], fx【i + begins【i】【j】】)

源代码

#include <iostream>
#include <vector>
using namespace std;

vector<int> begins[10002];        //begin存在时刻i开始的任务结束的时间
int fx[10002];                   //存储每个时间点的最大空闲值
int main()
{
    int i, j;
    int n, k;                    //n为工作日的持续时间,k为任务数
    cin >> n >> k;
    int be, co;
    for (i = 0;i < k;i++)
    {
        cin >> be >> co;
        begins[be].push_back(co);
    }

    for (i = n; i >= 1; i--) 
    {//倒序处理每个时刻
        if (!begins[i].empty())
        {//说明有任务需要做
            for (j = 0; j < begins[i].size(); j++)
            {//获取时间最长的那一个
                fx[i] = max(fx[i], fx[i + begins[i][j]]);
            }
        }
        else 
        {//否则就是没有任务,为空闲时间
            fx[i] = fx[i + 1] + 1;
        }
    }
    cout << fx[1] << endl;
    return 0;
}

文章作者: 陈细利
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 陈细利 !
评论
 上一篇
[每日算法]摆花 [每日算法]摆花
题目描述小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花,从 1 到 n 标号。为了在门口展出更多种花,规定第 i 种花不能超过ai 盆,摆花时同一种花放在一起,且
2021-04-07
下一篇 
[每日算法]过河卒 [每日算法]过河卒
题目描述棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。 棋盘用坐标表示,A 点 (0,
2021-03-28
  目录