HDU3905 Sleeping



                                                                         Sleeping


题目链接:Click Here~

题目分析:

   又是一道DP题,每次都是一眼看穿,每次都是不会正确推出状态转移方程式。悲剧。。~-~

   说有一个搞ACM的人,天天逃课搞ACM。但是快到期末了,他为了学分只能去上课了。由于他是熬夜刷题,所以他总是在课堂上睡觉(orz)。为了学分,他决定不能继续睡下去了。于是他制定了一个计划,就是在一堂课的n分钟中连续的听老师讲课不小于L分钟,但是每堂课睡觉时间不能少于m分钟(毕竟不是神啊,还是需睡觉地-_-)。而且每堂课每分钟都有一个学分值,现在要你求出在满足了上面的要求下如何得到最大的学分。学分是主要啊!这个大家都懂的。


算法分析:

   我个人感觉跟那个啥,跟HDU的Sum plus plus有点像。就是要运用到相同的思想,但是差别还是有点的,就是Sum plus plus更难一点。说说这题如何推状态转移方程式吧。

   我们用dp[i][j]表示前i分钟睡觉用了j分钟的最大学分值。

=====>>则可以推出一个状态:dp[i][j] = max(dp[i-1][j-1],dp[i-1][j]+a[i]);

      这个的意思是在第i分钟是睡还是不睡,去其中的最大值。而我们知道其中不睡还有分两种情况,这就是这道题的精髓所在,也就是为什么我说跟Sum plus plus有点像的原因。

第一种:把第i分钟不睡的值归入到前面的不睡的时间中。(在i分钟里连续听课的时间不一定大于L)

第二种:以第i分钟结尾,把前i-L作为开始听课的起点。且我们必须保证前提i-L>=j(因为至少要保证有前i分钟又j分钟的睡觉时间啊!)。

为什么要这么麻烦的分两种情况呢?你如果认真思考过,应该就会知道了。如果,直接求得话时间复杂度是O(N^3)。

  所以,最后我们会得到最后的状态是:

   d[i][j] = max{d[i-1][j]+a[i](接着前面不睡的时间),dp[i-L][j]+sum[i]-sum[i-L](以i-L作为不睡的起点)}。

最后吐槽一下HDU的判题系统,我看到有的人写的程序都超数组下界了还可以AC。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 1e3 + 5;
int dp[maxn][maxn],d[maxn][maxn];
int sum[maxn],a[maxn];
int n,L,m;
int Solve()
{
    memset(dp,0,sizeof(dp));
    memset(d,0,sizeof(d));
    for(int i = 1;i <= n;++i){
        for(int j = 0;j<=i&&j <= m;++j){
            if(i-ll >= j)
              d[i][j] = max(d[i-1][j]+a[i],dp[i-ll][j]+sum[i]-sum[i-ll]);    //不睡的最大收益
            if(j>=1)             //注意这里!!
              dp[i][j] = max(d[i][j],dp[i-1][j-1]);
            else
              dp[i][j] = d[i][j];
//            printf("j-1---> %d\n",j-1);
        }
    }
    return dp[n][m];
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&L))
    {
        sum[0] = 0;
        for(int i = 1;i <= n;++i){
            scanf("%d",&a[i]);
            sum[i] = sum[i-1]+a[i];
        }
        printf("%d\n",Solve());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值