1. 程式人生 > 其它 >2015年第六屆藍橋杯C/C++B組省賽題目-生命之樹

2015年第六屆藍橋杯C/C++B組省賽題目-生命之樹

技術標籤:c++演算法

在X森林裡,上帝建立了生命之樹。

他給每棵樹的每個節點(葉子也稱為一個節點)上,都標了一個整數,代表這個點的和諧值。
上帝要在這棵樹內選出一個非空節點集S,使得對於S中的任意兩個點a,b,都存在一個點列 {a, v1, v2, …, vk, b} 使得這個點列中的每個點都是S裡面的元素,且序列中相鄰兩個點間有一條邊相連。

在這個前提下,上帝要使得S中的點所對應的整數的和儘量大。
這個最大的和就是上帝給生命之樹的評分。

經過atm的努力,他已經知道了上帝給每棵樹上每個節點上的整數。但是由於 atm 不擅長計算,他不知道怎樣有效的求評分。他需要你為他寫一個程式來計算一棵樹的分數。

「輸入格式」
第一行一個整數 n 表示這棵樹有 n 個節點。
第二行 n 個整數,依次表示每個節點的評分。
接下來 n-1 行,每行 2 個整數 u, v,表示存在一條 u 到 v 的邊。由於這是一棵樹,所以是不存在環的。

「輸出格式」
輸出一行一個數,表示上帝給這棵樹的分數。

「樣例輸入」

5
1 -2 -3 4 5
4 2
3 1
1 2
2 5

「樣例輸出」

8

「資料範圍」
對於 30% 的資料,n <= 10
對於 100% 的資料,0 < n <= 10^5, 每個節點的評分的絕對值不超過 10^6 。

資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 3000ms

請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。

所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。

注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。

提交時,注意選擇所期望的編譯器型別。

主要思想是:遞迴到樹的最下層,從下往上遍歷檢索

程式碼:

#include <iostream>
#include <vector>
#define MAXN 100005
typedef
long long ll; using namespace std; ll w[MAXN];//儲存每個節點的評分 vector<ll> g[MAXN];//標記兩連通的節點 ll wi[MAXN];// ll ans=-10000; void dfs(ll root,ll father) { wi[root]=w[root];//獲取節點的評分 for(int i=0;i<g[root].size();i++) { ll son=g[root][i];//獲取與之聯通節點的編號 if(son!=father) {//思想是從下往上遍歷 dfs(son,root);//在這裡一直進入到最下層 if(wi[son]>0) wi[root]+=wi[son];//此節點評分為自己與子代評分之和 } } if(wi[root]>ans) ans=wi[root]; } int main() { int n; cin>>n; for(int i=1;i<=n;i++) cin>>w[i];//給每個節點從1到n編號,儲存每個節點的評分 for(int j=1;j<=n-1;j++) { ll x,y; scanf("%lld %lld",&x,&y); g[x].push_back(y);//標記存在通路的節點編號 g[y].push_back(x); } dfs(1,0); cout<<ans<<endl; return 0; }

詳見:https://blog.csdn.net/qq_40570410/article/details/105353025