動態規劃 樹形動態規劃 結點選擇

2022-03-13 06:03:03 字數 1556 閱讀 7994

題目

有一棵 n 個節點的樹,樹上每個節點都有乙個正整數權值。如果乙個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?

第一行包含乙個整數 n 。

接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。

接下來一共 n-1 行,每行描述樹上的一條邊。

輸出乙個整數,代表選出的點的權值和的最大值。

51 2 3 4 5

1 21 3

2 42 5

選擇3、4、5號點,權值和為 3+4+5 = 12 。

資料規模與約定

對於20%的資料, n <= 20。

對於50%的資料, n <= 1000。

對於100%的資料, n <= 100000。

權值均為不超過1000的正整數。

引言:這是我第一次接觸到的樹形dp題,一開始完全沒有思路。

後面看了看網上大佬的題解,頗有啟發。

dp的關鍵就在於狀態的定義以及找轉移

首先要考慮清楚狀態,狀態要能夠很好地並且完整地描述子問題

其次考慮最底層的狀態,這些狀態一般是最簡單的情況或者是邊界情況

再就是考慮某乙個狀態能從哪些子狀態轉移過來,同時還要考慮轉移的順序,確保子問題已經解決

樹形dp很多時候就是通過子節點推父親節點的狀態

分析:於是我們用乙個f[i][k]表示到以i為根的子樹中的最佳答案。

同時k=1時表示選這個節點,k=0時表示不選這個節點。

那麼,如果用u表示父節點,v表示它的乙個子節點時

容易得到

f[u][0]+=max(f[v][0],f[v][1]);

f[u][1]+=f[v][0];

也可以得知:

初始化時,f[i][0]=0;f[i][1]=w[i];

最終狀態為max(f[1][0],f[1][1])//要麼選根節點要麼不選

可是怎麼一步步推出此狀態呢?

這就要我們先深搜到它每乙個葉節點在一步步退回來。

同時節點數比較大,這就要求我們用鄰接表存樹。

#include #include #include #include #include using namespace std;

int head[100100];//表頭,head[i]代表起點是i的邊的編號

int cnt;//代表邊的編號

int f[1000][1000];

struct s

edge[100010];

void add(int u,int v)//向所要連線的表中加入邊

void dfs(int u,int pre)//pre--父節點 u起點

}int main()

dfs(1,-1);//從第乙個節點開始

cout《相信大家也注意到了。

if(pre==v)continue;//若父節點與終點重合(即為葉節點)則不需dp

如果是葉節點的話就不用遞推。

這算是最基本的樹形dp了,不難理解卻也讓大家明白了樹形dp與以往題目是有很大不同的。

結點選擇(樹形動態規劃)

現在對於樹形動態規劃理解的還不是很透徹,只能先做幾個題目練習一下 本題很重要的兩個方面乙個是建樹,這個需要邊和點的相互配合,乙個點兩條邊的表示都要標記。第二個很重要的方面是動態規劃的變化,本題首先想到的一成一成的樹,要不是子集的結合,要不就是自己本身,上乙個點要不是自己本身,要不是自己和子節點的子節...

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

問題描述 有一棵 n 個節點的樹,樹上每個節點都有乙個正整數權值。如果乙個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?輸入格式 第一行包含乙個整數 n 接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。接下來一共 n 1 行,每行描述樹上的一條邊。...

結點選擇 (藍橋杯 樹形動態規劃)

問題描述 有一棵 n 個節點的樹,樹上每個節點都有乙個正整數權值。如果乙個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?輸入格式 第一行包含乙個整數 n 接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。接下來一共 n 1 行,每行描述樹上的一條邊。...