SRM 666 Div1 EasyWalkOverATree
Problem Statement
Given is a tree on n nodes. The nodes are numbered 0 through n-1. You are given the description of the tree as a int[] parent with n-1 elements. For each valid i, there is an edge between vertices (i+1) and parent[i].
A person is currently standing in node 0. In a single step, the person can move from its current node to any adjacent node. You are given an int L. The person is allowed to make at most L steps.
Return the maximum number of nodes the person can visit during the walk. Node 0 (where the walk starts) and the node where the walk ends count as visited. Each visited node is only counted once, even if it is visited multiple times.
Definition
- ClassWalkOverATree
- MethodmaxNodesVisited
- Parametersvector<int> , int
- Returnsint
- Method signatureint maxNodesVisited(vector<int> parent, int L)
Limits
- Time limit (s)2.000
- Memory limit (MB)256
Constraints
- parent will contain between 0 and 49 elements, inclusive.
- For each i, parent[i] will be between 0 and i, inclusive.
- L will be between 1 and 100, inclusive.
Test cases
-
- parent{ 0, 0 }
- L2
Returns 2The tree consists of edges 1-0 and 2-0. Our person will start in node 0 and can make at most L=2 steps. In two steps, the best we can do is visit one of the nodes 1 and 2. -
- parent{ 0, 0 }
- L3
Returns 3This is the same tree, only now we have L=3. In three steps the person can visit all three nodes: for example, by going from node 0 to node 1, back to node 0, and finally to node 2. Note that even though the person visited node 0 twice, we only count it once. -
- parent{ 0, 1, 2, 3 }
- L2
Returns 3 -
- parent{ 0, 0, 0, 0, 2, 4, 2, 3, 1 }
- L1
Returns 2 -
- parent{ 0, 0, 1, 2, 3, 2, 3, 1, 3, 0, 1, 8, 6, 8, 0, 5, 15, 0, 9 }
- L4
Returns 5 -
- parent{ 0, 0, 0, 1, 1, 3, 5, 1, 4, 5, 2, 2, 10, 5, 10, 10, 11, 13, 8, 3, 18, 15, 20, 20, 23, 8, 11, 26, 4 }
- L26
Returns 17 -
- parent{ 0, 0, 2, 0 }
- L100
Returns 5As the tree is very small and L large, the person can easily visit all nodes. -
- parent{ 0, 0, 2 }
- L4
Returns 4
题解:http://apps.topcoder.com/wiki/display/tc/SRM+666
When maximizing the number of visited nodes using L steps, we want to minimize the number of nodes visited more than once. Let's think of the maximal path that doesn't visit any nodes more than once (A simple path). In a tree with maximum depth d , the maximum simple path starting at node 0 (the root) would contain d+1 nodes:

So the most nodes we can visit using this strategy is d+1 nodes, using L steps. If L≤d , then we should use this strategy to visit L+1 nodes - The most we can. This would be optimal because each node costs exactly one step, which is the minimum possible. The issue comes when d>L , now it might be possible to visit more than the d+1 nodes in the largest simple path. Imagine we want to visit just one additional node, this will necessarily cost us at least 2 more steps:

It doesn't matter which additional node we pick or what order we try to visit, visiting one more node will costs us two more steps. This is true whenever we want to add any new node to the walk. We can show this by using invariants. As an invariant we have an existing set of nodes that we know we can visit using x steps. Then we decide to add one more node to the walk, one whose parent is in the walk. Find the position of the parent node in the walk and insert going to the new node and returning to the walk, increasing the number of steps to x+2 . After this change, the invariant remains.
Therefore, you start with one node in the walk (the root 0), the first d nodes you add to the walk cost one step. Any additional node costs 2 steps. What is the maximum number of nodes you can reach using at most L steps? After the first d steps we have L−d steps left. Every two steps out of the L−d steps adds one node: ⌊L−d2⌋ (rounding down). The maximum number of nodes is: 1+d+⌊L−d2⌋ . However, sometimes L is so large that this formula can give a result larger than n so we just fix this small issue: min(n,1+d+⌊L−d2⌋) .
The solution consists of finding d and then using the formula. Don't forget the corner case when d≥L :
int maxNodesVisited(vector<int> parent, int L)
{
int n = parent.size() + 1;
// Find d, maximum distance from root to a leaf:
int d = 0;
// start with a leaf i and count the number of parents between it and the root:
for (int i = 1; i < n; i++) {
int c = 1;
int x = i;
while (parent[x-1] != 0) {
x = parent[x-1];
c++;
}
// remember the maximum c:
d = std::max(d, c);
}
if (d >= L) {
return L + 1;
}
return min(n, 1 + d + (L - d) / 2);
}