【dp 重要*】尼克的任务

【dp 重要*】尼克的任务_第1张图片


大致思路

刚开始我就是觉得好难啊,我觉得蓝桥杯的大题可能就这个差不多了!但是我真的没想出来,我还想是不是要用啥子拓扑排序哦,他确实是很“线性”的,但是拓扑排序只是指明“先后关系”,你这儿弄么复杂多样的先后关系真的不好建图的。

咋法用“线性dp”做嘛?

其实,别忽略了:背包问题也是线性dp。而这道题,是有点背包问题的感觉的——做不做这个任务,要求的是最大空暇时间。

这里就要对这种问题再增强一些理解了:首先我们还是老样子,让dp[i]表示1~i时刻的最大空暇时间,那么现在来结合题意想想尼克的选择(对于背包问题是拿和不拿)以及状态转移:对于这个问题是:如果当前时刻没有任务,则空暇时间dp[i]=dp[i-1]+1;如果当前时刻有任务,如果做任务则dp[i]=???这里就懵逼了,我当前时刻做任务和之前的时刻有啥子关系呢?只跟我后面的结束时间有关即dp[结束i]=dp[开始i] 。但是很显然这样改的话,首先状态转移的一个结构就乱了,再来,如果有多个任务,我还得用max函数,但dp[结束i]在之前并没有赋值,咋个比较出个最大值最优解从而晓得选择做哪个任务喃?

因此,需要从后往前来遍历。即需要修改dp[i]的含义——i~n时刻的最大空暇时间。这样我通过比较dp[开始i] 多个dp[结束i] (而dp[结束i]都已知)就能知道选择做哪个任务最优了。而空闲的时候dp[i]=dp[i+1]+1就是对的,因为含义变了嘛。 


AC代码(直接copy的,本人赶时间0.0):

#include  
#include  
using namespace std;  
long int n,k,sum[10001],num=1,f[10001];  
struct ren//结构体,一起排序 ,从大到小   
{  
    long int ks,js;  
};  
ren z[10001];  
int cmp(ren a,ren b)  
{  
    return a.ks>b.ks;  
}  
int main()  
{  
    long int i,j;   
    cin>>n>>k;  
    for(i=1;i<=k;i++)  
    {  
    cin>>z[i].ks>>z[i].js;    
    sum[z[i].ks]++;  
    }  
    sort(z+1,z+k+1,cmp);  
    for(i=n;i>=1;i--)//倒着搜   
    {  
        if(sum[i]==0)  
        f[i]=f[i+1]+1;  
        else for(j=1;j<=sum[i];j++)  
        {  
            if(f[i+z[num].js]>f[i])  
            f[i]=f[i+z[num].js];  
            num++;//当前已扫过的任务数   
        }  
    }  
    cout<

你可能感兴趣的:(蓝桥杯)