通向自由的钥匙

通向自由的钥匙被放n个房间里,这n个房间由n-1条走廊连接。但是每个房间里都有特别的保护魔法,在它的作用下,我无法通过这个房间,也无法取得其中的钥匙。虽然我可以通过消耗能量来破坏房间里的魔法,但是我的能量是有限的。那么,如果我最先站在1号房间(1号房间的保护魔法依然是有效的,也就是,如果不耗费能量,我无法通过1号房间,也无法取得房间中的钥匙),如果我拥有的能量为P,我最多能取得多少钥匙?

输入数据
    第一行包含两个非负整数,第一个为N,第二个为P。
    接下来n行,按1~n的顺序描述了每个房间。第i+1行包含两个非负整数cost和keys,分别为第i件房取消魔法需要耗费的能量和房间内钥匙的数量。
    接下来n-1行,每行两个非负整数x,y,表示x号房间和y号是连通的。

输出数据
    一行一个整数,表示取得钥匙的最大值。

样例
输入:key.in
5 5
1 2
1 1
1 1
2 3
3 4
1 2
1 3
2 4
2 5

输出: key.out
7

一道树形dp基础题。

dfs后,两层循环都要倒着枚举。第一层循环是因为分组背包要倒着,第二层循环是因为有c = 0的情况。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxn = 105;
21 inline ll read()
22 {
23   ll ans = 0;
24   char ch = getchar(), last = ' ';
25   while(!isdigit(ch)) last = ch, ch = getchar();
26   while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
27   if(last == '-') ans = -ans;
28   return ans;
29 }
30 inline void write(ll x)
31 {
32   if(x < 0) x = -x, putchar('-');
33   if(x >= 10) write(x / 10);
34   putchar(x % 10 + '0');
35 }
36 void MYFILE()
37 {
38 #ifndef mrclr
39   freopen("key.in", "r", stdin);
40   freopen("key.out", "w", stdout);
41 #endif
42 }
43 
44 int n, p;
45 int c[maxn], k[maxn];
46 struct Edge
47 {
48   int nxt, to;
49 }e[maxn << 1];
50 int head[maxn], ecnt = -1;
51 void addEdge(int x, int y)
52 {
53   e[++ecnt] = (Edge){head[x], y};
54   head[x] = ecnt;
55 }
56 
57 ll dp[maxn][maxn];
58 void dfs(int now, int f)
59 {
60   for(int i = c[now]; i <= p; ++i) dp[now][i] = k[now];     //赋初值
61   for(int i = head[now]; i != -1; i = e[i].nxt)
62     {
63       if(e[i].to == f) continue;
64       dfs(e[i].to, now);
65       for(int j = p; j >= c[now]; --j)
66       for(int h = j; h >= c[now]; --h)
67           dp[now][j] = max(dp[now][j], dp[now][h] + dp[e[i].to][j - h]);
68     }
69 }
70 
71 int main()
72 {
73   MYFILE();
74   Mem(head, -1);
75   n = read(); p = read();
76   for(int i = 1; i <= n; ++i) c[i] = read(), k[i] = read();
77   for(int i = 1; i < n; ++i)
78     {
79       int x = read(), y = read();
80       addEdge(x, y); addEdge(y, x);
81     }
82   dfs(1, 0);
83   write(dp[1][p]), enter;
84   return 0;
85 }
View Code

还自己yy了一个O(nv)的算法,虽然过了,然而忘了怎么写的……

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxn = 105;
21 inline ll read()
22 {
23   ll ans = 0;
24   char ch = getchar(), last = ' ';
25   while(!isdigit(ch)) last = ch, ch = getchar();
26   while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
27   if(last == '-') ans = -ans;
28   return ans;
29 }
30 inline void write(ll x)
31 {
32   if(x < 0) x = -x, putchar('-');
33   if(x >= 10) write(x / 10);
34   putchar(x % 10 + '0');
35 }
36 void MYFILE()
37 {
38 #ifndef mrclr
39   freopen("key.in", "r", stdin);
40   freopen("key.out", "w", stdout);
41 #endif
42 }
43 
44 int n, p;
45 int c[maxn], k[maxn];
46 struct Edge
47 {
48   int nxt, to;
49 }e[maxn << 1];
50 int head[maxn], ecnt = -1;
51 void addEdge(int x, int y)
52 {
53   e[++ecnt] = (Edge){head[x], y};
54   head[x] = ecnt;
55 }
56 
57 ll dp[maxn][maxn];
58 void dfs(int now, int f, int x)
59 {
60   if(x < 0) return;
61   for(int i = head[now]; i != -1; i = e[i].nxt)
62     {
63       if(e[i].to == f) continue;
64       for(int j = 0; j <= x; ++j) dp[e[i].to][j] = dp[now][j];
65       dfs(e[i].to, now, x - c[e[i].to]);
66       for(int j = c[e[i].to]; j <= p; ++j)
67       dp[now][j] = max(dp[now][j], dp[e[i].to][j - c[e[i].to]] + k[e[i].to]);
68     }
69 }
70 
71 int main()
72 {
73   MYFILE();
74   Mem(head, -1);
75   n = read(); p = read();
76   for(int i = 1; i <= n; ++i) c[i] = read(), k[i] = read();
77   for(int i = 1; i < n; ++i)
78     {
79       int x = read(), y = read();
80       addEdge(x, y); addEdge(y, x);
81     }
82   addEdge(0, 1);
83   dfs(0, -1, p);
84   write(dp[0][p]), enter;
85   return 0;
86 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9894985.html