老爷机 DP

题目链接:http://acm.nefu.edu.cn/contestShow.php

比赛的时候没写出来的题,想着建树深搜一下,无奈TLE又MLE(QAQ),再看题解,原来正解是DP。%%%%

题目大意:
在老爷机上玩游戏,每天有固定的时间,每款游戏有固定的开始和结束时间,不能中途离开游戏,也不能在游戏中途开始游戏,并且空闲的时候有游戏开始就必须玩。有游玩时间最长与游玩时间最短两种策略,一天选择了一种,下一天必须选择另一种,并且要尽可能地玩,问老爷机又多长时间是不被玩的。

解题思路:
首先看到这题可能会想到贪心,但是其实贪心并不可以废话为什么呢,因为每次空闲的时候有游戏开始的话,必须选择一个游戏玩,这样就导致此刻的选择具有后效性,这样的话贪心就不适用了。所以我们要用DP,但是这里要注意的是要逆推而不能正推,因为之前的选择会对之后产生影响,但是之后并不会对之前产生影响。题目要求老爷机的空闲时间,那我们就设dp[i]为从 i~n+1 的空闲时间,如果此刻空闲,转移方程为 dp[i]=dp[i+1]+1。如果此刻有游戏开始,转移方程dp1[i]=max(dp1[i],dp1[a[k].r])与dp2[i]=min(dp2[i],dp2[a[k].r]);
最后输出 4dp2[1]+3dp1[1]。

完整AC代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
struct node
{
    int l,r;
}a[maxn];
int cnt[maxn];
int dp1[maxn];
int dp2[maxn];
bool cmp(node p,node q)
{
    if(p.l==q.l)
    return p.r>q.r;
    return p.l>q.l;
}
int main()
{
    int t,n;
    scanf("%d %d",&t,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d %d",&a[i].l,&a[i].r);
        cnt[a[i].l]++;
    }
    sort(a+1,a+1+n,cmp);
    int k=1;
    for(int i=t;i>=1;i--)
    {
        if(!cnt[i])
        {
            dp1[i]=dp1[i+1]+1;
            dp2[i]=dp2[i+1]+1;
        }
        else
        {
            dp1[i]=dp1[a[k].r];
            dp2[i]=dp2[a[k++].r];
            for(int j=1;j<cnt[i];j++)
            {
                dp1[i]=max(dp1[i],dp1[a[k].r]);
                dp2[i]=min(dp2[i],dp2[a[k++].r]);
            }
        }
    }
    printf("%d\n",4*dp2[1]+3*dp1[1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/105923407
DP
DP?
今日推荐