P1280

P1280 尼克的任务

思路

思考线程1

这题自己还是没有想出来该怎么做,这道题其实刚开始理解一下是可以从任务的角度去dp?就是类似前面的最长子序列一样dp[n],但是题解上基本都是按dp[T]来的,这个选择就很让人费解,首先知道,题目问什么dp数组就存什么东西,但这个下标的选取并没有很强的规律性,只能启发式的总结成题目中数值形的且按小单位递增的东西,例如钱和时间.然后是这个dp转移方程的理解:
如 果 该 时 刻 s t [ i ] = = 0 则 d p [ i ] = d p [ i + 1 ] + 1 如果该时刻st[i] == 0 则dp[i]=dp[i+1]+1 st[i]==0dp[i]=dp[i+1]+1
如 果 该 时 刻 s t [ i ] ! = 0 则 d p [ i ] = m a x ( d p [ i + m i s s i o n [ j ] . d u r a t i o n ] , d p [ i ] ) 如果该时刻st[i] != 0 则dp[i] = max(dp[i+mission[j].duration], dp[i]) st[i]!=0dp[i]=max(dp[i+mission[j].duration],dp[i])
但是怎么理解这两个转移方程和题目问的

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

主要难点在于为什么顺推不行,而倒推就可以,首先顺推不行是因为在某个状态dp[i],这一刻选择的任务必然会影响到之后的选择,(如果做类比的话,原来背包问题dp[i]= max(dp[i], dp[i - item.cost]+item.value)这里是i-item.cost,是从之前的格子转移过来的,所以必须顺推,但是好像也不能这么理解,0-1背包的内层循环就是逆推的,

思考线程2

假设自己已经聪明到用dp[i]代表i-T的最大空余时间而且义无反顾的用了逆推,那么 d p [ i ] = d p [ i + 1 ] + 1 dp[i] = dp[i+1]+1 dp[i]=dp[i+1]+1这个式子能顺理成章的推出来吗,就是相当于此刻没有任务,这个还是能够想清的,然后是 d p [ i ] = m a x ( d p [ i ] , d p [ i + m i s s i o n [ j ] . d u r a t i o n ] ) dp[i] = max(dp[i], dp[i+mission[j].duration]) dp[i]=max(dp[i],dp[i+mission[j].duration]),这个转移能看懂,主要是怎么解决的向后影响的问题,因为题目不是说如果当前在做着任务,就不用考虑新的任务吗!!!不用管,因为首先当前考虑的任务的选择不会影响之后的选择(但这个不具有共性,最长不下降的选择和背包的选择自然会影响后面的选择,不然也不叫动态规划了,所以并不能说不会影响之后的选择,关键是理解这个状态的

思考线程3(第二天了)

就是说更新转态的话,那么出现在等式右边的状态必然要在之前就被更新,不然就不叫状态转移方程了呗.完事

code

#include <algorithm>
#include <bits/stdc++.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
const int maxn = 100000+5;
int dp[maxn];
struct node
{
    int start;
    int duration;
  bool operator < (const node&b) const
  {
      return start<b.start;
  }
};
node mission[100000+5];
int main() 
{
#ifdef LOCAL
    freopen("C:\\Users\\hsxny\\Desktop\\in.txt", "r", stdin);
#endif
int N,K;
int st[10000+5]={0};
scanf("%d%d",&N,&K);
for(int i=0;i<K;i++)
{
    node& temp = mission[i];
    scanf("%d%d",&temp.start, &temp.duration);
    st[temp.start]++;
}
sort(mission, mission+K);


for(int i=N;i>=1;i--)
{
    if(st[i] == 0)
    {
        dp[i] = dp[i+1]+1;
    }
    else
    {
        for(int j=1;j<=K;j++)
        {
            if(mission[j].start==i)    dp[i]= max(dp[i+mission[j].duration],dp[i]);        
        }
    }
}

printf("%d", dp[1]);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值