問題描述
有一棵 n 個節點的樹,樹上每個節點都有一個正整數權值。如果一個點被選擇了,那么在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?
輸入格式
第一行包含一個整數 n 。
接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。
接下來一共 n-1 行,每行描述樹上的一條邊。
輸出格式
輸出一個整數,代表選出的點的權值和的最大值。
樣例輸入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
樣例輸出
12
樣例說明
選擇3、4、5號點,權值和為 3+4+5 = 12 。
數據規模與約定
對于20%的數據, n <= 20。
對于50%的數據, n <= 1000。
對于100%的數據, n <= 100000。
權值均為不超過1000的正整數。
這是一題樹形DP的題目, 首先給出狀態轉移方程:
dp[i][2], 1代表選擇i, 0代表不選擇i
i代表父節點, j代表子節點, 當選擇i節點時, j節點必然不選擇, 當不選擇i節點時, 則比較選擇j節點和不選擇j節點的情況選擇大的
dp[i][1] = dp[j][0]
dp[i][0] = max(dp[j][0], dp[j][1])
一開始題沒看仔細, 以為輸入在前的代表父節點, 輸入在后的代表子節點, 所以就錯了:
#include <bits/stdc++.h>
#define MAXN 100010
using namespace std;
int dp[MAXN][2], father[MAXN];
bool visited[MAXN];
int n, root;
void treeDp(int node) {
visited[node] = true;
for(int i = 1; i <= n; i++) {
if(!visited[i] && father[i] == node) {
treeDp(i);
dp[node][1] += dp[i][0];
dp[node][0] += max(dp[i][0], dp[i][1]);
}
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &dp[i][1]);
}
int f, c;
bool begin = true;
root = 0;
for(int i = 1; i < n; i++) {
scanf("%d%d", &f, &c);
father[c] = f;
if(root == c || begin) {
root = f;
begin = true;
}
}
while(father[root]) {
root = father[root];
}
treeDp(root);
int ans = max(dp[root][0], dp[root][1]);
printf("%d\n", ans);
return 0;
}
還是too young too simple啊, 這里只是告訴了兩個節點形成了一條邊, 并沒有告訴誰是父節點, 誰是子節點, 所以這里需要使用前向星來存儲樹
#include <bits/stdc++.h>
#define MAXN 100010
using namespace std;
struct {
int v;
int next;
}edge[MAXN * 2];
int dp[MAXN][2], head[MAXN];
int M;
void add(int from, int to) {
edge[M].v = to;
edge[M].next = head[from];
head[from] = M++;
edge[M].v = from;
edge[M].next = head[to];
head[to] = M++;
}
void treeDp(int x, int pre) {
for (int i = head[x]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if(pre == v)
continue;
treeDp(v, x);
dp[x][1] += dp[v][0];
dp[x][0] += max(dp[v][0], dp[v][1]);
}
}
int main() {
int n;
M = 0;
scanf("%d", &n);
memset(dp, 0, sizeof(dp));
memset(head, -1, sizeof(head));
for (int i = 1; i <= n; i++) {
scanf("%d", &dp[i][1]);
}
int c, f;
for(int i = 1; i < n; i++) {
scanf("%d%d", &c, &f);
add(c, f);
}
treeDp(1, -1);
int ans = max(dp[1][0], dp[1][1]);
printf("%d\n", ans);
return 0;
}