算法题目——游历魔法王国

链接:https://www.nowcoder.com/questionTerminal/f58859adc39f4edc9cd8e40ba4160339
来源:牛客网
魔法王国一共有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]间有一条道路连接。
输出描述: 输出一个整数,表示小易最多能游历的城市数量。
分析 题目经过抽象之后,意思是在一个树中进行遍历,经过指定步数,可以获取最长经过节点树量的路径。如果把这个树按照根节点进行悬挂,可能更好理解一些。虽然有些答案是从低向上生长,但是我还是重建了树,采用悬挂树来做的。
从这个根节点开始遍历,先判断左树深度大还是右树深度大,先遍历树深度大的那个节点。直到步数用完为止。
树的深度通过后序遍历很容易求出来,结果发现这样的答案只能通过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

错在这个用例上了。这个正确答案是41,通过简单的贪心算法只能得到39个城市。
后来看了解析也是看不太懂。总之之后看到正确答案中是求出来深度后直接获得最终答案。
假设我们已经求出了每一个节点的最大深度,用deep[i]来表示,树的最下面一层的深度是1。
显然,根节点到任意一个节点的最长路径=deep[0]-1。
以这条路径为基础,我们可以额外访问一些节点。但是每次访问完这些节点的时候,我们必须回来这个路径。这一来一回,每次访问一个节点都必须额外走两步,访问两个节点就必须走4步。
看图就容易明白一些:
image.png 【算法题目——游历魔法王国】参考代码
#include #include using namespace std; vector > tree; vector 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> num; tree[num].push_back(i+1); } /* 计算深度 */ 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; }

    推荐阅读