题目大意
题目链接:[刷油漆][1]
题目分析
状态优化。
//dp[node][i]表示以node为根的子树中选择i个节点,且节点相互连通,所能达到的value和的最大值。
//注意i要从大到小进行枚举,且j一定小于i,不能等于i,因为node节点必须被占用
for (int i = M; i >= 2; i--) {
for (int j = 1; j < i; j++) {
dp[node][i] = dp[node][i] > dp[node][i - j] + dp[v][j] ? dp[node][i] : dp[node][i - j] + dp[v][j];
}
}
实现
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
struct Edge {
int to;
int next;
};
int gNodeValue[105];
int dp[105][105];
int gHead[105];
bool gVisited[105];
int gValue[105];
Edge gEdges[220];
int gEdgeIndex;
void InsertEdge(int u, int v) {
int e = gEdgeIndex++;
gEdges[e].to = v;
gEdges[e].next = gHead[u];
gHead[u] = e;
e = gEdgeIndex++;
gEdges[e].to = u;
gEdges[e].next = gHead[v];
gHead[v] = e;
}
int min(int a, int b) {
return a < b ? a : b;
}
void Dfs(int node, int m) {
gVisited[node] = true;
int e = gHead[node];
dp[node][1] = gValue[node];
for (e; e != -1; e = gEdges[e].next) {
int v = gEdges[e].to;
if (!gVisited[v]) {
Dfs(v, m);
for (int i = m; i >= 2; i--) {
for (int j = 1; j < i; j++) {
dp[node][i] = dp[node][i] > dp[node][i - j] + dp[v][j] ? dp[node][i] : dp[node][i - j] + dp[v][j];
}
}
}
}
}
void Init() {
memset(gValue, 0, sizeof(gValue));
memset(dp, 0, sizeof(dp));
memset(gValue, false, sizeof(gVisited));
memset(gEdges, -1, sizeof(gEdges));
gEdgeIndex = 0;
memset(gSuccessorNum, 0, sizeof(gSuccessorNum));
memset(gHead, -1, sizeof(gHead));
}
int main() {
int n, m;
Init();
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &gValue[i]);
}
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d %d", &u, &v);
InsertEdge(u, v);
}
Dfs(1, m);
printf("%d\n", dp[1][m]);
return 0;
}