Starship Troopers
分类:
dfs and similar
dp
trees
1.题意概述
- 出每个房间拥有的BUG数和能得到的能量数,然后给出每个房间的树形联通图,要到下一个房间必须攻破上一个房间,每个士兵最多消灭20个BUG,就算不足20个BUG也要安排一个士兵。
2.解题思路
- 树形dp入门题,对于每个房间,除去它本身需要的士兵,其他士兵就可以提供给它的子房间(子树),而子房间的最优选择也提供给了父节点,设 dp[i][j] 表示以i为根派j个士兵的最大价值,那么转移方程就是 dp[i][j]=max(dp[i][j−k]+dp[son[i]][k])
3.AC代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 101
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
int cost[N], brain[N], dp[N][N], n, m; // dp[u][p] p个士兵占领以u为根节点的概率最大值
vector<int> mp[N];
void dfs(int u, int pa)
{
for (int i = cost[u]; i <= m; i++)
dp[u][i] = brain[u];
int sz = mp[u].size();
for (int i = 0; i < sz; i++)
{
int v = mp[u][i];
if (v != pa)
{
dfs(v, u);
for (int j = m; j >= cost[u]; j--)
for (int k = 1; k <= j - cost[u]; k++)
dp[u][j] = max(dp[u][j], dp[u][j - k] + dp[v][k]);
}
}
}
int main()
{
while (~scanf("%d%d", &n, &m), n != -1 && m != -1)
{
for (int i = 0; i < n; i++)
{
int bug;
scanf("%d%d", &bug, &brain[i]);
cost[i] = (bug + 19) / 20;
mp[i].clear();
}
for (int i = 0; i < n - 1; i++)
{
int u, v;
scanf("%d%d", &u, &v);
u--;
v--;
mp[u].push_back(v);
mp[v].push_back(u);
}
if (m == 0)
{
puts("0");
continue;
}
memset(dp, 0, sizeof dp);
dfs(0, -1);
printf("%d\n", dp[0][m]);
}
return 0;
}