通向自由的钥匙(key)hgoi0407 题解
题目描述
- 通向自由的钥匙被放 n 个房间里,这 n 个房间由 n-1 条走廊连接。但是每个房间里都有特别的保
护魔法,在它的作用下,我无法通过这个房间,也无法取得其中的钥匙。虽然我可以通过消耗能量来
破坏房间里的魔法,但是我的能量是有限的。那么,如果我最先站在 1 号房间(1 号房间的保护魔法
依然是有效的,也就是,如果不耗费能量,我无法通过 1 号房间,也无法取得房间中的钥匙),如果我
拥有的能量为 P,我最多能取得多少钥匙?
输入
- 第一行包含两个非负整数,第一个为 N,第二个为 P。
接下来 n 行,按 1~n 的顺序描述了每个房间。第 i+1 行包含两个非负整数 cost 和 keys,分别
为第 i 件房取消魔法需要耗费的能量和房间内钥匙的数量。
接下来 n-1 行,每行两个非负整数 x,y,表示 x 号房间和 y 号是连通的。
输出
- 一行一个整数,表示取得钥匙的最大值。
样例
- 输入样例
- 5 5
1 2
1 1
1 1
2 3
3 4
1 2
1 3
2 4
2 5 - 输出样例
- 7
- 数据范围
- 对于 20%的测试数据,有 n<=20
对于 30%的测试数据,有 n<=30
对于所有测试数据,有 p,n<=100, cost <= Maxint, keys<= Maxint
题目解析
- 这题与course几乎是同一道题,做完course秒解。
选课 ( course ) hgoi0407 题解 - 本题也是基础的树形动归,我读入时先用了邻接矩阵存储了整个树,再递推转化成二叉树。
- 解题时先获取该二叉树的后序遍历,从树的底下向上递推,确保dp的无后效性。
- 方程:f [ i ] [ j ] = k存储了以i为根从底下开始有j能量 钥匙最大值为k
所以 f [ i ] [ j ] = max { f [ i.left ] [ j - k - i.cost ] + f [ i.right ] [ k ] + val [ i ] , f [ i.right ] [ k ] } ( 0 <= k <= j - i.cost )
附上AC程序
时间复杂度 O ( p^2 * n )
空间复杂度 O ( p^2 )
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define LIMIT 101
void finit(){
freopen("key.in","r",stdin);
freopen("key.out","w",stdout);
}
struct roomD{
roomD():val(0),cost(0),left(0),right(0){}
int val,cost,left,right;
};
roomD binary[LIMIT];
int f[LIMIT][LIMIT],n,p,rlq[LIMIT],rlqord=0,root;
bool vstd[LIMIT];
bool map[LIMIT][LIMIT];
void make_binary(int a,int b){
if (binary[a].left==0){
binary[a].left=b;
}else{
int temp=binary[a].left;
while (binary[temp].right!=0)
temp=binary[temp].right;
binary[temp].right=b;
}
}
void get_rlq(int ord){
if (binary[ord].left!=0)
get_rlq(binary[ord].left);
if (binary[ord].right!=0)
get_rlq(binary[ord].right);
rlq[rlqord++]=ord;
}
int main(){
finit();
cin>>n>>p;
for (int i=1;i<=n;i++){
cin>>binary[i].cost>>binary[i].val;
}
int t1,t2;
for (int i=1;i<n;i++){
cin>>t1>>t2;
map[t1][t2]=map[t2][t1]=true;
}
queue<int> q;
q.push(1);
while (!q.empty()){
int t=q.front();
q.pop();
if (vstd[t]) continue;
vstd[t]=true;
for (int i=1;i<=n;i++)
if ((!vstd[i])&&map[t][i]){
q.push(i);
make_binary(t,i);
}
}
make_binary(0,1);
get_rlq(0);
for (int j=0;j<=p;j++)
for (int i=0;i<n;i++){
int curr=rlq[i];
int cost=binary[curr].cost;
f[curr][j]=f[binary[curr].right][j];
for (int k=0;k<=j-cost;k++)
if (f[curr][j]<f[binary[curr].left][j-k-cost]+f[binary[curr].right][k]+binary[curr].val){
f[curr][j]=f[binary[curr].left][j-k-cost]+f[binary[curr].right][k]+binary[curr].val;
}
}
cout<<f[rlq[n-1]][p]<<'\n';
return 0;
}