藍橋杯 演算法訓練 結點選擇

2021-08-15 08:12:34 字數 1924 閱讀 1253

**

題目:

問題描述

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

輸入格式

第一行包含乙個整數 n 。

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

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

輸出格式

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

樣例輸入

51 2 3 4 5

1 21 3

2 42 5

樣例輸出

12樣例說明

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

資料規模與約定

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

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

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

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

看過這道題,我們大概可以知道,這是一道和樹有關的問題,那麼我們需要考慮的就是如何去遍歷樹?很明顯,我們需要用到dfs。仔細讀這道題,然後我們就可以得到這還需要用到動態規劃,由此,我們做這道題,解題方案也就是樹形動態規劃了!

既然要用動態規劃,構造狀態轉移方程是必不可少了! 

對於葉子結點: 

dp[k][0] = 0; 

dp[k][1] = k點權值; 

對於非葉子結點: 

dp[i][0] = max(dp[j][0], dp[j][1]); (j是i的兒子) 

dp[i][1] = i點權值 + dp[j][0]; (j是i的兒子) 

最大權值即為: 

max(dp[0][0], dp[0][1])。(要麼不包括根結點,要麼包括根結點)

**如下:

#include 

#include

#define _max 100010

#define max(a, b) a > b ? a : b

struct point

edge[_max * 2]; //一條邊記錄兩次,分別以乙個點做記錄

int head[_max];

int m;

int dp[_max][2];

//新增乙個邊

void addedge(int from, int to)

//深度遍歷,先深入到葉子結點,然後一層一層往上回公升,一直到根結點,即第乙個結點(初始pre為-1是因為根結點沒有父結點,用-1表示)

void dfs(int x, int pre)

dfs(v, x); //x可以理解為父結點

//深度遍歷到最裡面的葉子結點的父結點 如果父結點選擇,則子結點不選擇,否則子結點可能選擇或者不選擇,但是要比較兩者哪個**擇哪個

dp[x][1] += dp[v][0]; // 父結點(選) += 子結點(不選)

dp[x][0] += max(dp[v][0], dp[v][1]); // 父結點(不選) += max(子結點(不選),子結點(選))

}return ;

}int main(int argc, const

char * argv)

//輸入邊,並且新增edge,乙個邊新增兩個edge

for (i = 1; i < n; i++)

dfs(1, -1); //深度優先遍歷,從第乙個結點開始遍歷

tmp = max(dp[1][0], dp[1][1]); //求出最大的權值和

printf("%d\n", tmp);

return

0;}

具體的思路實現都注釋了,希望可以幫助理解。 

over!!!

藍橋杯 演算法訓練 結點選擇

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

藍橋杯 演算法訓練 結點選擇

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

藍橋杯 結點選擇

問題描述 有一棵 n 個節點的樹,樹上每個節點都有乙個正整數權值。如果乙個點被選擇了,那麼在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?解題思路 這題模型是樹形動態規劃入門題目,dp i 0 表示該節點不被選擇,dp i 1 表示該結點被選擇。轉移方程為 dp u 1 dp v 0 ...