1. 程式人生 > >算法訓練 結點選擇【樹形動態規劃】

算法訓練 結點選擇【樹形動態規劃】

back esp con header 最大值 amp define turn 輸出格式

問題描述

有一棵 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[1][u]+=dp[0][u_son]; dp[0][u]+=max(dp[0][u_son],dp[1][u_son]); 接觸樹形dp的第一道題!
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <vector>
#define
inf 100005 using namespace std; int w[inf];//記錄各點權重 vector<int> G[inf]; int d[2][inf]; //d[1][i] 為取第i個節點的最大值 //d[0][i] 為不取 bool vis[inf]; int n;//節點個數 void dfs(int u) { vis[u] = 1; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i];//u的第i個兒子 if (vis[v])continue
; dfs(v); d[1][u] += d[0][v]; d[0][u] += max(d[0][v], d[1][v]); } d[1][u] += w[u]; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &w[i]); int a, b; for (int i = 0; i < n - 1; i++) { scanf("%d %d", &a, &b); G[a].push_back(b); G[b].push_back(a); } dfs(1); cout << max(d[0][1], d[1][1]); return 0; }

算法訓練 結點選擇【樹形動態規劃】