鏈接:https://www.nowcoder.com/questionTerminal/f58859adc39f4edc9cd8e40ba4160339
來源:牛客網(wǎng)
魔法王國(guó)一共有n個(gè)城市,編號(hào)為0~n-1號(hào),n個(gè)城市之間的道路連接起來恰好構(gòu)成一棵樹。
小易現(xiàn)在在0號(hào)城市,每次行動(dòng)小易會(huì)從當(dāng)前所在的城市走到與其相鄰的一個(gè)城市,小易最多能行動(dòng)L次。
如果小易到達(dá)過某個(gè)城市就視為小易游歷過這個(gè)城市了,小易現(xiàn)在要制定好的旅游計(jì)劃使他能游歷最多的城市,請(qǐng)你幫他計(jì)算一下他最多能游歷過多少個(gè)城市(注意0號(hào)城市已經(jīng)游歷了,游歷過的城市不重復(fù)計(jì)算)。
輸入描述:
輸入包括兩行,第一行包括兩個(gè)正整數(shù)n(2 ≤ n ≤ 50)
和L(1 ≤ L ≤ 100)
,表示城市個(gè)數(shù)和小易能行動(dòng)的次數(shù)。
第二行包括n-1
個(gè)整數(shù)parent[i](0 ≤ parent[i] ≤ i)
, 對(duì)于每個(gè)合法的i(0 ≤ i ≤ n - 2)
,在(i+1)
號(hào)城市和parent[i]
間有一條道路連接。
輸出描述:
輸出一個(gè)整數(shù),表示小易最多能游歷的城市數(shù)量。
分析
題目經(jīng)過抽象之后,意思是在一個(gè)樹中進(jìn)行遍歷,經(jīng)過指定步數(shù),可以獲取最長(zhǎng)經(jīng)過節(jié)點(diǎn)樹量的路徑。如果把這個(gè)樹按照根節(jié)點(diǎn)進(jìn)行懸掛,可能更好理解一些。雖然有些答案是從低向上生長(zhǎng),但是我還是重建了樹,采用懸掛樹來做的。
從這個(gè)根節(jié)點(diǎn)開始遍歷,先判斷左樹深度大還是右樹深度大,先遍歷樹深度大的那個(gè)節(jié)點(diǎn)。直到步數(shù)用完為止。
樹的深度通過后序遍歷很容易求出來,結(jié)果發(fā)現(xiàn)這樣的答案只能通過60%。
45 73
0 0 0 1 0 0 3 5 6 8 7 9 1 10 1 2 15 6 8 11 14 17 8 14 3 21 23 3 21 15 12 5 21 31 11 13 7 17 20 26 28 16 36 26
錯(cuò)在這個(gè)用例上了。這個(gè)正確答案是41,通過簡(jiǎn)單的貪心算法只能得到39個(gè)城市。
后來看了解析也是看不太懂。總之之后看到正確答案中是求出來深度后直接獲得最終答案。
假設(shè)我們已經(jīng)求出了每一個(gè)節(jié)點(diǎn)的最大深度,用deep[i]來表示,樹的最下面一層的深度是1。
顯然,根節(jié)點(diǎn)到任意一個(gè)節(jié)點(diǎn)的最長(zhǎng)路徑=deep[0]-1。
以這條路徑為基礎(chǔ),我們可以額外訪問一些節(jié)點(diǎn)。但是每次訪問完這些節(jié)點(diǎn)的時(shí)候,我們必須回來這個(gè)路徑。這一來一回,每次訪問一個(gè)節(jié)點(diǎn)都必須額外走兩步,訪問兩個(gè)節(jié)點(diǎn)就必須走4步。
看圖就容易明白一些:
參考代碼
#include <vector>
#include <iostream>
using namespace std;
vector<vector<int> > tree;
vector<int> deep;
void calc_deep(int i)
{
int max_deep = 0;
for(auto j:tree[i])
{
calc_deep(j);
max_deep = max(deep[j], max_deep);
}
deep[i] = max_deep + 1;
}
int main()
{
int n, L;
cin >> n >> L;
/* 建立樹 */
tree.resize(n);
deep.resize(n);
for(int i=0;i<n-1;i++)
{
int num;
cin >> num;
tree[num].push_back(i+1);
}
/* 計(jì)算深度 */
calc_deep(0);
// int validpath = min(deep[0] -1,L);
// cout << min(n, 1 + validpath + (L - validpath)/2) << endl;
int long_path = deep[0] - 1;
if(long_path > L) cout << L + 1;
else cout << 1 + long_path + (L - long_path)/2;
}