题意:
一颗有n个节点的树,每个节点有val值和c(1-有陷阱,0-无陷阱)值,给出最大可踩陷阱数k。在树中任取一点作为起点,经过某点就取得该点的val值,
踩到第k个陷阱后马上停止,而且不能走已走过的点。
求最大累计val值。
暴力方法:每点进行一次深搜求最大值。(这样竟然可以过= =,703ms)
树形DP:
子问题:最大值转化为求一个节点某子树的最大值和树的其他部分的最大值和。
状态:dp[u][j]表示从以u为根,从u子树中某点走到u经过j个陷阱时的最大val值。
难点:与“不超过 k 个求最大的长度”不同的是,该题是达到k个就马上停止
所以增加一维表示方向,即dp[u][j][0]表示从非陷阱点走到u,dp[u][j][1]表示从陷阱点走到u
更详细解释,见代码注释
一颗有n个节点的树,每个节点有val值和c(1-有陷阱,0-无陷阱)值,给出最大可踩陷阱数k。在树中任取一点作为起点,经过某点就取得该点的val值,
踩到第k个陷阱后马上停止,而且不能走已走过的点。
求最大累计val值。
暴力方法:每点进行一次深搜求最大值。(这样竟然可以过= =,703ms)
树形DP:
子问题:最大值转化为求一个节点某子树的最大值和树的其他部分的最大值和。
状态:dp[u][j]表示从以u为根,从u子树中某点走到u经过j个陷阱时的最大val值。
难点:与“不超过 k 个求最大的长度”不同的是,该题是达到k个就马上停止
所以增加一维表示方向,即dp[u][j][0]表示从非陷阱点走到u,dp[u][j][1]表示从陷阱点走到u
更详细解释,见代码注释
暴力:

1 #include <cstdio>
2 #include <cstring>
3 #define N 50005
4
5 struct Edge
6 {
7 int e, next;
8 }edge[N*2];
9
10 int head[N], eNum;
11 int c[N], val[N], n, k, ans;
12
13 void init()
14 {
15 memset(head, -1, sizeof(head));
16 eNum = 0; ans = 0;
17 }
18
19 void AddEdge(int u, int v)
20 {
21 edge[eNum].e = v;
22 edge[eNum].next = head[u];
23 head[u] = eNum++;
24 }
25
26 int max2(int x, int y)
27 {
28 return x > y ? x : y;
29 }
30
31 void dfs(int u, int fa, int cur, int cc)
32 {
33 if(cc>k) return;
34 if(cc==k)
35 {
36 ans = max2(ans, cur);
37 return;
38 }
39 ans = max2(ans, cur);
40 for(int i=head[u]; i!=-1; i=edge[i].next)
41 {
42 int v = edge[i].e;
43 if(v==fa) continue;
44 dfs(v, u, cur + val[v], cc + c[v]);
45 }
46 }
47
48 int main()
49 {
50 int t;
51 scanf("%d",&t);
52 while(t--)
53 {
54 scanf("%d%d",&n,&k);
55 for(int i=0; i<n; i++)
56 scanf("%d%d",&val[i],&c[i]);
57 init();
58 int u, v;
59 for(int i=0; i<n-1; i++)
60 {
61 scanf("%d%d",&u,&v);
62 AddEdge(u, v);
63 AddEdge(v, u);
64 }
65 for(int i=0; i<n; i++)
66 {
67 dfs(i,-1,val[i],c[i]);
68 }
69 printf("%d ",ans);
70 }
71 return 0;
72 }
2 #include <cstring>
3 #define N 50005
4
5 struct Edge
6 {
7 int e, next;
8 }edge[N*2];
9
10 int head[N], eNum;
11 int c[N], val[N], n, k, ans;
12
13 void init()
14 {
15 memset(head, -1, sizeof(head));
16 eNum = 0; ans = 0;
17 }
18
19 void AddEdge(int u, int v)
20 {
21 edge[eNum].e = v;
22 edge[eNum].next = head[u];
23 head[u] = eNum++;
24 }
25
26 int max2(int x, int y)
27 {
28 return x > y ? x : y;
29 }
30
31 void dfs(int u, int fa, int cur, int cc)
32 {
33 if(cc>k) return;
34 if(cc==k)
35 {
36 ans = max2(ans, cur);
37 return;
38 }
39 ans = max2(ans, cur);
40 for(int i=head[u]; i!=-1; i=edge[i].next)
41 {
42 int v = edge[i].e;
43 if(v==fa) continue;
44 dfs(v, u, cur + val[v], cc + c[v]);
45 }
46 }
47
48 int main()
49 {
50 int t;
51 scanf("%d",&t);
52 while(t--)
53 {
54 scanf("%d%d",&n,&k);
55 for(int i=0; i<n; i++)
56 scanf("%d%d",&val[i],&c[i]);
57 init();
58 int u, v;
59 for(int i=0; i<n-1; i++)
60 {
61 scanf("%d%d",&u,&v);
62 AddEdge(u, v);
63 AddEdge(v, u);
64 }
65 for(int i=0; i<n; i++)
66 {
67 dfs(i,-1,val[i],c[i]);
68 }
69 printf("%d ",ans);
70 }
71 return 0;
72 }
树形DP:

1 #include <cstdio>
2 #include <cstring>
3 #define N 50005
4 #define INF 99999999
5
6 struct Edge
7 {
8 int e, next;
9 }edge[N*2];
10
11 int head[N], eNum;
12 int c[N], val[N], n, k, ans, dp[N][4][2];
13
14 void init()
15 {
16 memset(head, -1, sizeof(head));
17 eNum = 0; ans = 0;
18 for(int i=0; i<n; i++)
19 {
20 for(int j=0; j<4; j++)
21 {
22 for(int l=0; l<2; l++)
23 dp[i][j][l] = -INF;
24 }
25 }
26 }
27
28 void AddEdge(int u, int v)
29 {
30 edge[eNum].e = v;
31 edge[eNum].next = head[u];
32 head[u] = eNum++;
33 }
34
35 int max2(int x, int y)
36 {
37 return x > y ? x : y;
38 }
39
40 void dfs(int u, int fa)
41 {
42 dp[u][c[u]][c[u]] = val[u]; //初始化dp[u][0][0] 或 dp[u][1][1]
43 for(int i=head[u]; i!=-1; i=edge[i].next)
44 {
45 int v = edge[i].e;
46 if(v==fa) continue;
47 //先求从子节点子树到子节点的最大值
48 dfs(v, u);
49 //用u节点子树到u节点的最大值 和 从子节点子树到子节点的最大值 和 更新ans
50 for(int j=0; j<=k; j++) //-u
51 {
52 for(int l=0; l+j<=k; l++)//-v
53 {
54 ans = max2(ans, dp[u][j][1]+dp[v][l][1]); // 1 -> 1
55 if(j+l!=k) ans = max2(ans, dp[u][j][0]+dp[v][l][0]); // 0 -> 0
56 ans = max2(ans, dp[u][j][0]+dp[v][l][1]); // 0 -> 1 dp[v][0][1] 为-INF
57 ans = max2(ans, dp[u][j][1]+dp[v][l][0]); // 0 -> 1 dp[u][0][1] 为-INF
58 }
59 }
60 for(int j=0; j<k; j++)
61 {
62 dp[u][j+c[u]][1] = max2(dp[u][j+c[u]][1],dp[v][j][1]+val[u]); //用子节点更新u点
63 dp[u][j+c[u]][0] = max2(dp[u][j+c[u]][0],dp[v][j][0]+val[u]);
64 }
65 if(c[u]==0) dp[u][k][1] = max2(dp[u][k][1], dp[v][k][1]+val[u]); //这里漏了,存在ans = dp[v1][0][0] + dp[u][k][1]的可能
66 }
67 }
68
69 int main()
70 {
71 int t;
72 scanf("%d",&t);
73 while(t--)
74 {
75 scanf("%d%d",&n,&k);
76 for(int i=0; i<n; i++)
77 scanf("%d%d",&val[i],&c[i]);
78 init();
79 int u, v;
80 for(int i=0; i<n-1; i++)
81 {
82 scanf("%d%d",&u,&v);
83 AddEdge(u, v);
84 AddEdge(v, u);
85 }
86 dfs(0,-1);
87 printf("%d ",ans);
88 }
89 return 0;
90 }
2 #include <cstring>
3 #define N 50005
4 #define INF 99999999
5
6 struct Edge
7 {
8 int e, next;
9 }edge[N*2];
10
11 int head[N], eNum;
12 int c[N], val[N], n, k, ans, dp[N][4][2];
13
14 void init()
15 {
16 memset(head, -1, sizeof(head));
17 eNum = 0; ans = 0;
18 for(int i=0; i<n; i++)
19 {
20 for(int j=0; j<4; j++)
21 {
22 for(int l=0; l<2; l++)
23 dp[i][j][l] = -INF;
24 }
25 }
26 }
27
28 void AddEdge(int u, int v)
29 {
30 edge[eNum].e = v;
31 edge[eNum].next = head[u];
32 head[u] = eNum++;
33 }
34
35 int max2(int x, int y)
36 {
37 return x > y ? x : y;
38 }
39
40 void dfs(int u, int fa)
41 {
42 dp[u][c[u]][c[u]] = val[u]; //初始化dp[u][0][0] 或 dp[u][1][1]
43 for(int i=head[u]; i!=-1; i=edge[i].next)
44 {
45 int v = edge[i].e;
46 if(v==fa) continue;
47 //先求从子节点子树到子节点的最大值
48 dfs(v, u);
49 //用u节点子树到u节点的最大值 和 从子节点子树到子节点的最大值 和 更新ans
50 for(int j=0; j<=k; j++) //-u
51 {
52 for(int l=0; l+j<=k; l++)//-v
53 {
54 ans = max2(ans, dp[u][j][1]+dp[v][l][1]); // 1 -> 1
55 if(j+l!=k) ans = max2(ans, dp[u][j][0]+dp[v][l][0]); // 0 -> 0
56 ans = max2(ans, dp[u][j][0]+dp[v][l][1]); // 0 -> 1 dp[v][0][1] 为-INF
57 ans = max2(ans, dp[u][j][1]+dp[v][l][0]); // 0 -> 1 dp[u][0][1] 为-INF
58 }
59 }
60 for(int j=0; j<k; j++)
61 {
62 dp[u][j+c[u]][1] = max2(dp[u][j+c[u]][1],dp[v][j][1]+val[u]); //用子节点更新u点
63 dp[u][j+c[u]][0] = max2(dp[u][j+c[u]][0],dp[v][j][0]+val[u]);
64 }
65 if(c[u]==0) dp[u][k][1] = max2(dp[u][k][1], dp[v][k][1]+val[u]); //这里漏了,存在ans = dp[v1][0][0] + dp[u][k][1]的可能
66 }
67 }
68
69 int main()
70 {
71 int t;
72 scanf("%d",&t);
73 while(t--)
74 {
75 scanf("%d%d",&n,&k);
76 for(int i=0; i<n; i++)
77 scanf("%d%d",&val[i],&c[i]);
78 init();
79 int u, v;
80 for(int i=0; i<n-1; i++)
81 {
82 scanf("%d%d",&u,&v);
83 AddEdge(u, v);
84 AddEdge(v, u);
85 }
86 dfs(0,-1);
87 printf("%d ",ans);
88 }
89 return 0;
90 }