题意:
这是一个塔防游戏,地图是一个n个编号为1~n的节点的树, 节点1是敌人的基地,其他叶子节点都是你的基地。敌人的基地会源源不断地出来怪兽,为了防止敌人攻进你的基地,你可以选择造塔。每个节点最多只能造一个塔,且节点i可以有ki种塔供你选择,价钱和攻击力分别为price_i, power_i,攻击力power_i,效果是让敌人经过这个节点时让敌人的血减少power_i点。那么从敌人的基地到你的任意一个叶子基地的路径,这条路径上的所有塔的攻击力之和,就是这个基地的抵抗力。敌人的攻击路径是不确定的,为了保护你的所有基地,你要确定所有基地中抵抗力最低的一个。 你只有数量为m的钱,问最佳方案,可以抵挡敌人的最大血量是多少?也就是,让所有叶子基地中抵抗力最低的一个的值尽量大,最大是多少?
思路:
最大值最小化问题
dp[i][j]表示以节点i为根节点的子树有j元钱时的最大抵抗力,因为我们需要考虑将j元钱分配给i的子节点,所以在dfs的同时进行一次分组背包处理,结束以后在对节点进行01背包,最后dp[1][m]就是答案了。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f
int n,m;
int cnt;
int tot[maxn];
int head[maxn];
int dp[10005][300];
int num[maxn],cost[maxn][55],val[maxn][55];
struct Edge
{
int u,v,next,w;
}edge[maxn*2];
void addedge(int u,int v,int w)
{
cnt++;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
// void dfs1(int u,int pre)
// {
// dp[u][0]=inf;
// int t=0;
// for(int i=head[u];i!=-1;i=edge[i].next)
// {
// int v=edge[i].v;
// if(v==pre) continue;
// dfs1(v,u);
// for(int j=m;j>=0;j--)
// {
// t=0;
// for(int k=0;k<=j;k++)
// {
// t=max(t,min(dp[u][j-k],dp[v][k]));
// }
// dp[u][j]=t;
// }
// }
// if(dp[u][0]==inf) dp[u][0]=0;
// for(int j=m;j>=0;j--)
// {
// t=dp[u][j];
// for(int i=1;i<=price[u][0];i++)
// {
// if(j>=price[u][i])
// {
// t=max(t,dp[u][j-price[u][i]]+power[u][i]);
// }
// }
// dp[u][j]=t;
// }
// }
void dfs(int u,int fa)
{
dp[u][0]=INF;
int i,j,k,v,t;
for(i=head[u];i;i=edge[i].next)
{
v=edge[i].v;
if(v==fa) continue ;
dfs(v,u);
for(j=m;j>=0;j--)
{
t=0;
for(k=0;k<=j;k++)
{
t=max(t,min(dp[v][k],dp[u][j-k]));
}
dp[u][j]=t;
}
}
if(dp[u][0]==INF) dp[u][0]=0; // 一定要加这个判断
for(j=m;j>=0;j--)
{
t=dp[u][j];
for(i=1;i<=num[u];i++)
{
if(j>=cost[u][i])
{
t=max(t,dp[u][j-cost[u][i]]+val[u][i]);
}
}
dp[u][j]=t;
}
}
int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int i,j,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int u,v;
cnt=0;
memset(head,0,sizeof(head));
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v,0);
addedge(v,u,0);
}
scanf("%d",&m);
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
for(j=1;j<=num[i];j++)
{
scanf("%d%d",&cost[i][j],&val[i][j]);
}
}
memset(dp,0,sizeof(dp));
dfs(1,0);
printf("%d\n",dp[1][m]);
}
return 0;
}