問題の意味
タワーの防衛ゲーム、マップのツリーであるN(1-N)からなるノード、ノードが敵スポーンポイントで、すべてのリーフノードは、我々の塩基です。各ノードで異なる塔を構築することができていますが、各ノードは一つだけを構築することができます。
タワーズ価格と傷2つのプロパティを。ときに敵を介してノードは、ノードの塔のダメージ値を攻撃します。
与えられた資産
、求めに敵がノードのリーフを横断することができないことを確実にするための条件で敵の人生の最大値が、でも、パスのすべてのリーフノードへのノードから最小合計攻撃最大あれば、抵抗することができます。
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
問題の解決策
- 定義状態: を表し ノード、支出 内の最大かつ最小攻击力。
- 各ノードの前処理: iノード上の花ことを示し タワーを建設の費用対効果の最大の害を得ることができます
- 状態遷移:各非リーフノードの場合、その状態は、そのすべての子ノードの源です。レッツ・ドローは、それが上記の塔の場合ではない状態、その後に来るタワー状態。
- タワーを建設しないでください。
- タワー:ナップザック問題
#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;
}