【題解】樹形dp NKOI1469 通向未來的鑰匙

水一發水一發



題目

題面

通向自由的鑰匙被放 n 個房間裏,這 n 個房間由 n-1 條走廊連接。但是每個房間裏都有
特別的保護魔法,在它的作用下,我無法通過這個房間,也無法取得其中的鑰匙。雖然我可
以通過消耗能量來破壞房間裏的魔法,但是我的能量是有限的。那麼,如果我最先站在 1
號房間(1 號房間的保護魔法依然是有效的,也就是,如果不耗費能量,我無法通過 1 號房
間,也無法取得房間中的鑰匙),如果我擁有的能量爲 P,我最多能取得多少鑰匙?

輸入數據

第一行包含兩個非負整數,第一個爲 N,第二個爲 P。
接下來 n 行,按 1~n 的順序描述了每個房間。第 i+1 行包含兩個非負整數 cost 和 keys,
分別爲第 i 件房取消魔法需要耗費的能量和房間內鑰匙的數量。
接下來 n-1 行,每行兩個非負整數 x,y,表示 x 號房間和 y 號是連通的。

輸出數據

一行一個整數,表示取得鑰匙的最大值。

樣例

輸入:key.in
5 5
1 2
1 1
1 1
2 3
3 4
1 2
1 3
2 4
2 5
輸出: key.out
7

數據範圍

對於 20%的測試數據,有 n<=20
對於 30%的測試數據,有 n<=30
對於所有測試數據,有 p,n<=100, cost <= Maxint, keys<= Maxint


題解

題意

n個點(n-1)條邊

顯然建樹。
題目可看作簡單的樹上揹包,多叉轉二叉後
有p塊錢,分配給兒子和兄弟錢數,求最大獲利即可

需要注意的

只是需要稍微提一下到建樹方式 我纔不會說我主要調試這裏去了
又沒說給出的x,y中前面的就是父親,後面就是兒子
需要先記錄點與點之間的聯通,之後掃一遍,掃到的兒子遞歸處理即可


代碼

就是樹形dp模板題,調了一下午
老年OI選手要退役了

#include <cstdio>
#include <cstring>

const int maxn = 110;

int cost[maxn], keys[maxn];
int son[maxn], bro[maxn];
int dp[maxn][maxn];
bool vis[maxn];
int n;

inline void Swap(int &a, int &b){int t = a; a = b, b = t;}
void Line(int rt){
    int i = 1, fg = 0;
    while (!dp[rt][i] && i <= n) ++i;
    if (i > n) return ;
    dp[i][rt] = 0, son[rt] = i;
    Line(i); int ls = i;
    for (++i; i <= n; ++i){
    if (dp[rt][i]){
        dp[i][rt] = 0, Line(i);
        bro[ls] = i, ls = i;
    }
    }
}
int f(int rt, int pw){
    if (!rt || pw < 0) return 0;
    if (dp[rt][pw] != -1) return dp[rt][pw];

    int res = f(bro[rt], pw);
    int res1;
    for (int i = cost[rt]; i <= pw; ++i){
    res1 = f(son[rt], i - cost[rt]) + f(bro[rt], pw - i) + keys[rt];
    if (res1 > res) res = res1;
    }
    return dp[rt][pw] = res;
}
int main (){
    freopen ("key.in", "r", stdin);
    freopen ("key.out", "w", stdout);

    int p; scanf ("%d%d", &n, &p);
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= n; ++i) scanf ("%d%d", cost + i, keys + i);
    memset(vis, 0, sizeof(vis));
    for (int i = 1, x, y; i < n; ++i){
    scanf ("%d%d", &x, &y);
    dp[x][y] = dp[y][x] = 1;
    }
    Line(1);

    memset(dp, -1, sizeof(dp));
    printf ("%d", f(1, p));

    return 0;
}

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