1. 程式人生 > 其它 >試題 演算法訓練 結點選擇

試題 演算法訓練 結點選擇

技術標籤:藍橋杯演算法刷題演算法c++

試題 演算法訓練 結點選擇

問題描述

資源限制
時間限制: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()函式。