题意
一个塔防游戏里,地图是n个结点组成的树(1-n),其中1节点是敌人的出生点,所有叶子节点是我方基地。在每个节点上都有不同的防御塔可以建造,但每个节点最多只能造一座。
防御塔有 价格 和 伤害 两种属性。敌人经过一个结点时会受到该节点的防御塔的伤害数值的攻击。
给定资产
m
m
m,求在保证没有敌人能越过叶子节点的条件下,所能抵御的敌人的最大生命值,即使 从1节点到所有叶子节点路径上的最小的攻击总和 最大。
2
2
1 2
30
3 10 20 20 40 30 50
3 10 30 20 40 30 45
4
2 1
3 1
1 4
60
3 10 20 20 40 30 50
3 10 30 20 40 30 45
3 10 30 20 40 30 35
3 10 30 20 40 30 35
70
80
题解
- 定义状态: d p [ i ] [ j ] dp[i][j] dp[i][j]表示在 i i i节点上,花费在 j j j以内的最大的最小攻击力和。
- 预处理每个节点: m a x _ d m g [ i ] [ j ] max\_dmg[i][j] max_dmg[i][j]表示在i节点上花 j j j费用建塔所能得到的最大伤害效益
- 状态转移:对于每一个非叶节点,它的状态来源是它所有的子节点。我们先得出不在它上面建塔的情况的状态,再得出建塔的状态。
- 不建塔: d p [ x ] [ p ] = max ( min ( d p [ v ] [ k ] ) ∣ ∑ k = p , v ∈ s o n s ( x ) , v 1 ≠ v 2 ) dp[x][p] =\max( \min(dp[v][k])\ |\ \sum k=p,v∈sons(x), v1 \ne v2) dp[x][p]=max(min(dp[v][k]) ∣ ∑k=p,v∈sons(x),v1=v2)
- 建塔:背包问题
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pr pair<int, int>
const int maxn=4000, maxp=250;
int n, m, T, ans;
int a[maxn];
int dp[maxn][maxp];
int max_dmg[maxn][maxp];
struct node{
int v, next;
}e[maxn*2];
int head[maxn], cnt;
void add(int u, int v)
{
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
void dfs(int x, int fa)
{
int num = 0;
for(int i=head[x];i!=-1;i=e[i].next)
{
int v = e[i].v;
if(v==fa) continue;
num++;
dfs(v, x);
for(int j=m;j>=0;j--)
{
int t = 0;
for(int k=0;k<=j;k++)
{
// 先考虑x节点不建塔的情况
t = max(t, min(dp[v][k], dp[x][j-k]));
// dp[x][j] = max( min( dp[v][k] | sum(k) = j ) )
// 划分j的费用给x点和它的子节点v
}
dp[x][j] = t;
}
}
// 下面是在x上建塔的情况(在不建塔的情况的基础上)
if(!num){
dp[x][0] = 0;
for(int i=0;i<=m;i++)
dp[x][i] = max_dmg[x][i];
return;
}
for(int i=m;i>=0;i--)
{
for(int j=0;j<=i;j++)
{
dp[x][i] = max(dp[x][i-j]+max_dmg[x][j], dp[x][i]);
}
}
}
int main()
{
cin >> T;
int x, y;
while(T--)
{
cnt = 0;
memset(head, -1, sizeof head);
memset(max_dmg, 0, sizeof max_dmg);
cin >> n;
for(int i=0;i<n-1;i++)
{
cin >> x >> y;
add(x, y);
add(y, x);
}
cin >> m;
for(int i=1;i<=n;i++)
{
int K;
cin >> K;
for(int j=0;j<K;j++)
{
cin >> x >> y;
max_dmg[i][x] = max(max_dmg[i][x], y);
}
for(int j=1;j<=m;j++)
max_dmg[i][j] = max(max_dmg[i][j-1], max_dmg[i][j]);
}
memset(dp, 0x3f, sizeof dp);
dfs(1, 0);
cout << dp[1][m] << endl;
}
return 0;
}