1011 Starship Troopers(樹形dp)
阿新 • • 發佈:2018-12-18
題意:
有一個以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;
}