洛谷P1107[BJWC2008]雷涛的小猫题解

题目

这个题可以说是一个很基础偏中等的(DP)了,很像(NOIpD1T2)的难度,所以这个题是很好想的。

简化题意

可以先简化一下题意,这个题由于从上面向下调和从下向上爬都是一样的,所以我们就可以轻松的想到暴力的方法。

(dp[i][j])表示i编号的树的j高度从一开始跳最多能吃多少柿子,每次都选择(max)(当前这个树下面一格的柿子数,其他树下面跳(delta)格的柿子数)。

但是这样的时间复杂度是非常大的,主要就在我们在计算出每一高度的所有树的dp之后,下次我们再用到这些树的(dp)值时还需要再(O(n))枚举一下,因此就浪费了大量时间,而如果我们记录一个数组(maxn[i])表示i这个高度所有树的(dp)最大值,在计算时便可以更新,然后下次调用时便可直接调用了。

这就是记忆化的思想。

(Code)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m, h, del, a, data[4010][4010], dp[4010][4010], maxn[100100];//dp[i][j]表示从0开始第i棵树到达第j高度时最多可以吃到的柿子。
inline void init()
{
    scanf("%d%d%d", &n, &h, &del);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &m);
        for (int j = 1; j <= m; j++)
            scanf("%d", &a), data[i][a]++;
    }   
}
int main()
{		
     init();
     for (int k = 1; k <= h; k++)
        for (int i = 1; i <= n; i++)
        {
            if (k < del)
            dp[i][k] = dp[i][k - 1] + data[i][k], maxn[k] = max(maxn[k], dp[i][k]);
            else
        	dp[i][k] = max(dp[i][k - 1], maxn[k - del]) + data[i][k], maxn[k] = max(maxn[k], dp[i][k]);
        }
    printf("%d", maxn[h]);
}