zoukankan      html  css  js  c++  java
  • 1280 尼克的任务

    难度:普及+/提高

    题目类型:动规

    提交次数:1

    涉及知识:线性动规

    题目描述

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

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

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

    输入输出格式

    输入格式:

    输入数据第一行含两个用空格隔开的整数N和K(1≤N≤10000,1≤K≤10000),N表示尼克的工作时间,单位为分钟,K表示任务总数。

    接下来共有K行,每一行有两个用空格隔开的整数P和T,表示该任务从第P分钟开始,持续时间为T分钟,其中1≤P≤N,1≤P+T-1≤N。

    输出格式:

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

    代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector> 
     4 using namespace std;
     5 int n, k;
     6 struct task{
     7     int start;
     8     int last;
     9     int end;
    10 };
    11 bool com(task a, task b){
    12     return a.start<b.start;
    13 }
    14 int d[10010];//表示以第i个任务结尾的工作序列的最小消耗时间 
    15 int b[10010];//表示第i分钟开始的任务个数 
    16 int s[10010];//表示第1到i分钟的任务个数 
    17 int main(){
    18     cin>>n>>k;
    19     int i, j;
    20     vector<task>a(k+1);
    21     for(i = 1; i <= k; i++){
    22         int start, last, end;
    23         cin>>start>>last;
    24         end = start+last-1;
    25         a[i].start = start;
    26         a[i].end = end;
    27         a[i].last = last;
    28         b[start]++; 
    29     }
    30     sort(a.begin()+1, a.end(), com);
    31     
    32     for(i = 1; i <= n; i++)
    33         s[i] = s[i-1]+b[i];
    34     
    35     for(i = 1; i <=k; i++){
    36         d[i] = 10010;
    37         for(j = 0; j < i; j++){
    38             if(a[j].end<a[i].start&&s[a[j].end]==s[a[i].start-1])
    39                 d[i] = min(d[i], d[j]+a[i].last);
    40         }
    41     }
    42     int ans = 10010;
    43     for(i = 1; i <=k; i++){
    44         if(s[a[i].end]==s[n])
    45             ans = min(ans, d[i]);
    46     }
    47     cout<<n-ans<<endl;
    48         
    49     return 0;
    50 }

    备注:

    有思路后还是很清晰的一道题。最大空闲时间等价于求最少工作消耗时间。所以子问题是“以第i个任务为结尾的最少工作消耗时间”,在我的代码里用d[i]表示。状态怎样转移呢?引号内内容摘自洛谷题解,感觉说的非常清楚:

    “把任务按照开始时间排序,以确保如果某一时刻无其他任务必须做一个。

    f[i]=f[j]+cost(i) 仅当end(j)<start(i) 且 在区间(end(j),start(i))中无其他任务。

    使用cnt(i)表示从1-i时刻有几个任务,如果cnt(a)==cnt(b)则说明a,b间无任务。”

    一开始我居然不知道原问题的解是什么。。其实很简单啊,最后一个任务到工作时间结束之间没有其他任务开始的话,这就是一个完整的可行解。跟状态转移是一样的。

    在我的代码里s数组就是回答中的cnt数组。我觉得cnt数组的设置和处理是十分巧妙的(已标黄)。它的递推过程也体现了一点动规的思想。

    另外很巧妙的一点就是已标黄的“j=0”,这样一个小技巧就完美解决了在之前没有任务的情况下,最短消耗时间就是这个工作的消耗时间。

    最后吐槽一点,我居然不小心在if后加了分号,并且因为这个问题查了一个小时orz

  • 相关阅读:
    YAML序列样式
    YAML块标量头
    YAML字符流
    YAML语法字符
    YAML流程
    YAML集合和结构
    YAML缩进和分离
    YAML简介
    Git工作流程
    Git使用前配置
  • 原文地址:https://www.cnblogs.com/fangziyuan/p/5932314.html
Copyright © 2011-2022 走看看