1. 程式人生 > >1011 Starship Troopers(樹形dp)

1011 Starship Troopers(樹形dp)

題意:

有一個以1為根節點的數,每個節點都有N個怪物,和M個保障,你從1開始進入,在消滅一個房間的怪物之後才能向下走,你有K個士兵,一個士兵能打20個怪物,在一個房間留下一些士兵後,這些士兵就不能走了,你不能走已經走過的房間,問最多能獲得多少寶藏

思路:

很像樹形dp於是就用樹形dp寫了,dp[i][j] 表示第i個房間有j名士兵可以得到的最大寶藏, 假設進入一個節點前有M的士兵,這個節點消耗N個士兵,那麼,最多有M-N個士兵進入下面的房間,下面重複上面過程,直至進入葉子節點,如果葉子節點沒有怪物,那麼獲得寶藏需要派1名士兵進入葉子節點 對於1個房間的狀態轉移方程為 dp[i][N] = max(dp[i][N], dp[i][N-M] + dp[j][M])

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int inf = 0x3f3f3f3f;
const int maxn = 1005;

struct tree{
    int u, v, next;
}tree[maxn];

struct Point{
    int cost, num;
}p[maxn];

int head[maxn], tot;
int dp[105][105];
int N, M;

void dfs(int u, int v) {
    memset(dp[u]
, 0, sizeof(dp[u])); int cnt = 0; for (int i = head[u]; i + 1; i = tree[i].next) {//判斷是否為葉子節點 int son = tree[i].v; if(son == v) continue; cnt ++; } if(p[u].cost == 0 && !cnt) p[u].cost = 1;//如果為葉子節點並且p[u].cost為0,那麼修改值 for (int i = M; i >= p[u].cost; i --
) dp[u][i] = p[u].num;//初始化 for (int i = head[u]; i + 1; i = tree[i].next) { int son = tree[i].v; if(son == v) continue; dfs(son, u); for (int k = M; k >= p[u].cost; k --) { for (int j = 1; k - j >= p[u].cost; j ++) { dp[u][k] = max(dp[u][k], dp[u][k - j] + dp[son][j]);//狀態轉移 } } } } void add(int u, int v) { tree[tot].u = u; tree[tot].v = v; tree[tot].next = head[u]; head[u] = tot ++; tree[tot].u = v; tree[tot].v = u; tree[tot].next = head[v]; head[v] = tot ++; } int main(int argc, char const *argv[]) { while(cin >> N >> M && (N != -1 || M != -1)) { memset(head, -1, sizeof(head)); tot = 0; for (int i = 1; i <= N; i ++) { int x; cin >> x >> p[i].num; p[i].cost = x/20 + (x % 20 != 0); } for (int i = 1; i < N; i ++) { int u, v; cin >> u >> v ; add(u, v); } if(!M) { cout << 0 << endl; continue; } dfs(1, 0); cout << dp[1][M] << endl; } return 0; }