【洛谷】P1107 [BJWC2008]雷濤的小貓

【洛谷】P1107 [BJWC2008]雷濤的小貓

1.題意

給出若干棵樹,以及每棵樹不同高度有幾個柿子的信息。以及給出走法規則,求能夠獲取到最多的柿子數。

2.分析

  • 線形dp題
  • 問題抽象轉換

2.1 方法1

我自己的方法是:設 dp[i][j] 表示第j棵樹,高度爲i時獲得的最大值。然後三重循環遍歷一下,第三重循環的含義是從之前較高的樹上找出一個最大的值(一個最優解)。代碼如下:

 //dp計算
for(int i = h-delta;i>0;i--){//i爲高度
    for(int j = 1;j<=n;j++){//j爲樹的下標
        dp[i][j] = dp[i+1][j];//繼承
        for(int k = 1;k<=n;k++) { //找中間跳一次
            dp[i][j] = max(dp[i][j], dp[i + delta][k]);
        }
        dp[i][j] += fruit[j][i]; //加上當前的果子
    }
}

但是這個代碼會讓你 TLE,該如何簡化呢?可以看到這裏的最外層的for循環其實是高度從高到低,也就是說:較高層的最大值其實在除了第一次做j的循環時需要尋找,以後循環j的時候便不用再循環了,而是直接可以利用上一次找出的最大值,這個最大值放到rec[]中。rec[i]就表示高度爲i時能夠得到最大值。修改後的代碼如下3示。

2.2方法2

這是洛谷的大佬給出的想法:
將每棵樹的每個高度看成是一個圖的節點,然後進行一波圖節點的轉移操作,最後得到一個最優解。這裏的思想貴在抽象,能夠將所學的知識應用到實際的問題上!

3.代碼

// Created by lawson on 20-6-17.
#include<iostream>
#include<cstdio>
using namespace std;

const int maxN = 2005;
int dp[maxN][maxN];//dp[i][j]表示第j棵樹,高度爲i時獲得的最大值
int fruit[maxN][maxN];//fruit[i][j]表示第i棵樹,高度爲j時有柿子
int rec[maxN];//rec[i]用於記錄高度爲i時的最大值

int n,h,delta;
int main(){
    scanf("%d%d%d",&n,&h,&delta);
    for(int i = 1;i<= n;i++){//樹的下標
        int num,loc;//柿子數; 每個柿子所在的高度
        scanf("%d",&num);
        for(int j = 1;j<=num;j++)//柿子個數
        {
            scanf("%d",&loc);
            fruit[i][loc] ++;//高度爲loc,第i棵樹時有一個柿子
        }
    }

    for(int i = h;i>h-delta;i--){//高度爲i
        for(int j = 1;j<=n;j++){//樹的下標爲j
            dp[i][j] = fruit[j][i] + dp[i+1][j]; //本高度+上面高度繼承
        }
    }

    //dp計算
    for(int i = h-delta;i>0;i--){//i爲高度
        for(int j = 1;j<=n;j++){//j爲樹的下標
            dp[i][j] = dp[i+1][j];//繼承
            if(rec[i+delta]){ //如果之前高度爲 i+delta 時的最大值已經找到過了
                dp[i][j] = max(dp[i][j],rec[i+delta]);
            }
            else{//沒有記錄,第一次需要尋找
                for(int k = 1;k<=n;k++) { //找中間跳一次
                    dp[i][j] = max(dp[i][j], dp[i + delta][k]);
                }
                rec[i+delta] = dp[i][j];
            }
            dp[i][j] += fruit[j][i]; //加上當前的果子
        }
    }
    int res = 0;
    for(int i = 1;i<= n;i++)
        res = max(res,dp[1][i]);
    printf("%d\n",res);
}

4.測試用例

3 10 2
3 1 4 10
6 3 5 9 7 8 9
5 4 5 3 6 9

01.如何降維?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章