題目描述
魔法王國一共有n個城市,編號爲0~n-1號,n個城市之間的道路連接起來恰好構成一棵樹。小易現在在0號城市,每次行動小易會從當前所在的城市走到與其相鄰的一個城市,小易最多能行動L次。如果小易到達過某個城市就視爲小易遊歷過這個城市了,小易現在要制定好的旅遊計劃使他能遊歷最多的城市,請你幫他計算一下他最多能遊歷過多少個城市(注意0號城市已經遊歷了,遊歷過的城市不重複計算)。
輸入描述
輸入包括兩行,第一行包括兩個正整數n(2 ≤ n ≤ 50)和L(1 ≤ L ≤ 100),表示城市個數和小易能行動的次數。第二行包括n-1個整數parent[i](0 ≤ parent[i] ≤ i), 對於每個合法的i(0 ≤ i ≤ n - 2),在(i+1)號城市和parent[i]間有一條道路連接。
輸出描述
輸出一個整數,表示小易最多能遊歷的城市數量。
示例
輸入
5 2
0 1 2 3
輸出
3
解題代碼
拿到這道題,說實話,我也想了很久,甚至試了深度優先搜索,但是如果僅有簡單的數組數據結構,深度優先搜索是做不出maxLength,即一次搜索最長的長度。原因是我漏看了題目一個最重要的信息!不廢話,先上代碼,然後再一步步介紹如何做的。
#include<iostream>
#include<vector>
using namespace std;
int solveMaxLen(int, vector<int>, vector<int>);
int max(int, int);
int main(){
//思路:1、首先,先搜索出最長的深度,即每一次走都不走回頭路
int n, L, maxLength;
cin >> n >> L;
vector<int> parent;
vector<int> dp(n, 0);
int temp;
for (int i = 0; i < n - 1; i++){
cin >> temp;
//比如:parent[0]與1之間有一條邊相連
parent.push_back(temp);
}
maxLength = solveMaxLen(n, dp, parent);
//首先,如果L小於最長的深度,那麼就是說還沒走到最深處就停止了,那麼此時遊歷的國家就爲L+1
if (maxLength - 1>=L){
cout << L + 1;
}
//如果L大於最長的深度,那麼此時肯定會有重複走的路,對於某個點A來說,如果想繞彎來遊歷它,那麼就需要先走到A,然後再走到A的父節點,於是每遊歷一個要重複的國家,需要2次,所以
//(n - maxLength + 1)表示除了最長的深度上的節點外的其它節點,
//(n - maxLength + 1) * 2 + maxLength - 1表示如果要遊歷完所有國家的總次數,若總次數>L,那麼(L - maxLength + 1) / 2表示能遊歷的重複國家數,maxLength表示在最長的深度上的國家數
else if (maxLength - 1 < L && (n - maxLength + 1) * 2 + maxLength - 1 >= L){
cout << (L - maxLength + 1) / 2 + maxLength;
}
//如果L比要遊歷完所有國家所需的總次數還大,那麼就直接輸出所有的國家
else{
cout << n;
}
system("pause");
return 0;
}
int solveMaxLen(int n, vector<int> dp, vector<int> parent){
dp[0] = 1;
int maxLen = 0;
for (int i = 1; i < n; i++){
dp[i] = dp[parent[i-1]] + 1;
maxLen = max(maxLen, dp[i]);
}
return maxLen;
}
int max(int a, int b){
if (a > b){
return a;
}
else{
return b;
}
}
思路闡述
首先,回到題目中來,其實題目已經透露了很多隱藏信息:
1、“一棵樹”,讓人想到樹的數據結構;
2、“parent”是不是樹的父節點呢?那根據題目意思,parent[i]是不是第i+1個節點的父節點呢?答案是肯定的,因爲有一個約束 parent[i]必須 ≤ i,即如果遊歷的話,會先遊歷parent[i]再遊歷節點 i+1
於是,根據題目的意思,很容易想到dp(動態規劃),即訪問第i個節點時,可以先訪問parent[i-1]節點,再走一步到達節點i,dp[i] = dp[ parent[i-1] ]+1;根據這個公式,很容易就做出了樹的深度。
對於,判斷條件,我在代碼中已經註明了,大家可以參照我的代碼。