2015年第六屆藍橋杯C/C++B組省賽題目-生命之樹
阿新 • • 發佈:2021-01-21
在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;
}