試題 演算法訓練 結點選擇
阿新 • • 發佈:2021-01-16
試題 演算法訓練 結點選擇
問題描述
資源限制
時間限制:1.0s 記憶體限制:256.0MB
問題描述
有一棵 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的正整數。
解題思路
從葉子結點往上到根結點遍歷
1、 初始化每一個結點,對應選該結點和不選該結點兩種情況。
dp[k][0]=0,dp[k][1]=x;//x為k結點權值
;
2、 對於每個結點i,
3、 結果輸出的最大權值即為max(dp[1][0],dp[1][1] )
原始碼
#include <iostream> #include <vector> using namespace std; int n; int dp[100002][2]; vector<vector<int> > tree;//相當於二維不定長陣列 void dfs(int x,int x_f) { for(int i=0;i<tree[x].size();i++) { int x_s=tree[x][i]; if(x_s!=x_f) //不需要再遍歷已經遍歷過的父結點 { dfs(x_s,x); //一直往下走到葉子結點 dp[x][1]+=dp[x_s][0]; dp[x][0]+=max(dp[x_s][1],dp[x_s][0]); } } } int main() { cin>>n; //結點數量 for(int i=1;i<=n;i++) cin>>dp[i][1]; //設定在選擇第i個結點的情況下 i結點的權值 tree.resize(n+1); //設定不定長陣列陣列第一維的大小 int x,y; for(int i=1;i<n;i++) { cin>>x>>y; tree[x].push_back(y); tree[y].push_back(x); } dfs(1,0); cout<<max(dp[1][1],dp[1][0]) <<endl; return 0; }
總結
1、為什麼要if(x_s!=x_f) 這個判斷條件,其實就是為了不走迴路,比如1,2結點相連,1的子節點有2,那麼2往下走,就不需要再遍歷1了。
2、一個二維陣列的二維的長度不確定,可以使用vector<vector<int> > tree;
即定義一個不定長陣列tree的型別為不定長陣列。設定大小用resize()函式。