zoukankan      html  css  js  c++  java
  • P1280 尼克的任务[区间覆盖dp]

    题目描述

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

    尼克的一个工作日为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:

    15 6
    1 2
    1 6
    4 11
    8 5
    8 1
    11 5
    

    输出样例#1:

    4
    

    解析:

    写完这道题,我才感觉我真正理解了(dp)。。。

    (dp)最主要的还是阶段,状态,决策这三点,设计好了就没有问题,在做(dp)题时,一定要对状态空间有清晰的刻画,才能准确的写出转移方程。实际上由于最优子结构和无后效性,只用考虑上一个状态跟当前状态的关系,而我之前总是觉着(dp)作为一个解决问题的系统有那么点玄乎。。。


    显然这道题不能正推,由于子问题的最优解都是由一段段持续的时间决定的,也就是说当前的状态的转移可能会用到之后的状态,那就保不齐在还未求解出后面的状态时,前面的状态就用到了这个后面的尚未求解的状态,这在(dp)中是不被允许的。(dp)中,如果我们要求出下一阶段的最优解,那么本阶段的最优解就要先求出来。

    倒推就可以解决这种问题,由于在某个的时刻开始的每个任务,它们的起始时间都是确定的,它们的结束时间恰好落在曾经的解决过的子问题中。这样的话在逆推时,我们关注某个起始时刻时,可选择的任务就确定了,求解子问题所需的状态也是之前求出来过的。(可能这么说不准确,但我也不知道怎么讲了,自己细细品味)

    总之,倒推的话,当前状态就可以由之前的状态转移而来了。

    因此我们设(dp[i])(i-n)的最长空闲时间,那么,显然(dp[n]=0)即是初始状态。

    (i)时刻,可能有一些以此时刻为起点的任务,也可能没有。

    所以我们可以得到两个状态转移方程:

    • (dp[i]=dp[i+1]+1)。即当前时刻(i)没有任务,我们就继承上一时刻的最优解。

    • (dp[i]=max(dp[i],dp[i+a[num]])),其中(a[num])表示在时刻(i)时,之前已经执行过的任务的个数(num),以及当前任务的持续时间(a[num])。即当前时刻有任务,我们选取使得空闲时间最长的决策。

    参考代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<cstdlib>
    #include<queue>
    #include<vector>
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    #define N 10010
    #define MOD 2520
    #define E 1e-12
    using namespace std;
    int dp[N],n,k,t[N];
    struct node{
    	int p,t;
    }a[N];
    bool operator<(node a,node b)
    {
    	return a.p>b.p;
    }
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;i++){
    		scanf("%d%d",&a[i].p,&a[i].t);
    		t[a[i].p]++;
    	}
    	sort(a+1,a+k+1);
    	int num=1;
    	for(int i=n;i>=1;i--)
    	 if(t[i]==0) dp[i]=dp[i+1]+1;
    	 else for(int j=1;j<=t[i];j++){
    	 	dp[i]=max(dp[i],dp[i+a[num++].t]);
    	 }
    	cout<<dp[1]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    稳扎稳打Silverlight(47) 4.0UI之操作剪切板, 隐式样式, CompositeTransform, 拖放外部文件到程序中
    返璞归真 asp.net mvc (9) asp.net mvc 3.0 新特性之 View(Razor)
    返璞归真 asp.net mvc (6) asp.net mvc 2.0 新特性
    稳扎稳打Silverlight(48) 4.0其它之打印, 动态绑定, 增强的导航系统, 杂七杂八
    精进不休 .NET 4.0 (9) ADO.NET Entity Framework 4.1 之 Code First
    稳扎稳打Silverlight(42) 4.0控件之Viewbox, RichTextBox
    稳扎稳打Silverlight(53) 4.0通信之对WCF NetTcpBinding的支持, 在Socket通信中通过HTTP检索策略文件, HTTP请求中的ClientHttp和BrowserHttp
    稳扎稳打 Silverlight 4.0 系列文章索引
    稳扎稳打Silverlight(54) 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”
    返璞归真 asp.net mvc (8) asp.net mvc 3.0 新特性之 Model
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11146072.html
Copyright © 2011-2022 走看看