Algorithm Meituan Written Exam (2020-9-6) Staff Assignment
@author:Jingdai
@date:2020.11.18
Look at the Meituan written test a few days ago and record it. This question is the 4th question of the algorithm written test of Meituan on September 6.
Title description
The company has n employees, and the affiliation of n employees needs to be divided. The division requirements are as follows:
- Everyone either has no subordinates or at least 2 direct reports
- I-affiliated individuals (including myself) have
ai
aNote: Direct subordinates and subordinates (including themselves) can be regarded as the "son" and "subtree" of the employee, respectively, and ask whether there is such a relationship.
Enter a description:
The first line of input is an integer n (n<=24), which means that the company has n people.
N numbers in the next line, the i-th number is
ai
Ideas
This question is obviously a tree question, first analyze the specific meaning of the question. As shown in the figure, first look at a few examples that meet the requirements of the question and then look at it to better understand the meaning of the question.
For requirement 1, it actually means that for each non-leaf node in the tree, the number of its sons is required to be greater than or equal to 2. That is, the degree of each node in the tree cannot be equal to 1.
For in claim 2, meaning that each node value (
ai
) represents a sub-tree of the node (including its own) haveai
nodes. So for this root node of the tree, it represents the number of nodes in the entire tree, so the biggestai
is the root node, and if this constitutes a tree, the largestai
necessarily equal to n. The maximum can beai
performed if a pre-determined equal to n.Combined with claim 1 and claim 2, find
ai
if the value is equal to 2, it must not constitute such a tree, sinceai
a minimum of 1 (request 2), and a non-leaf nodes to include at least two leaf nodes, then the non-leaf nodes The minimum value is 3, so the preprocessing judgment can also be made according to whether the input value contains 2 or not.Next, let's look at how to solve this problem. Here we use the backtracking algorithm to solve it. First look at the definition of variables:
nodes
Array
nodes
Recording the input arrayai
values. First,nodes
in descending order, itnodes[0]
is the root of the tree, in addition tonodes[0]
all have the parent node. Here thenodes
values in the array assigned as the number of nodes required, such asnodes[i] = 6
representative of the subtree rooted at the node needed allocate 5 (own count 1) nodes; whennodes[i] = 1
Representative redistribution does not require a child of that node.
children
ArrayRecord the number of children of each node, which is used to finally determine whether the degree of each node is not 1.
unfinishedParentSet
setThis set represents need to set the child node's parent node assigned index, i.e.,
nodes[i] > 1
all nodes. When this set is empty, it means that there is no parent node that needs to be allocated.Next look at the algorithm. First pretreatment, as described above, for each input, if
ai
equal to 2, the representative does not constitute such a tree, after the input is completed, tonodes
be sorted in descending order, ifnodes[0]
not equal to n, the representative does not constitute such a tree.After the preprocessing is completed, proceed to the next step for those that cannot be judged. First traverse
nodes
the array, thenodes
array index is greater than 1 is addedunfinishedParentSet
. Then perform depth-first traversal and backtracking.As shown, the
nodes
element of the arraynodes[1]
(nodes[0]
the root node, has no parent node) attempts to allocate to startunfinishedParentSet
in the parent node, the parent FIG x nodes areunfinishedParentSet
in the node, a parent node allocation failure to try the next parent node, If it succeeds, it returns true, and if all parent nodes fail, it returns false.That attempt to allocate
nodes[i] -= nodes[child]
thechildren[i]
plus 1, and ifnodes[i]
the parent node is equal to 1 representing the assignment is completed, theunfinishedParentSet
deleting. If the attempt to allocate fails to backtrack, willnodes
,children
andunfinishedParentSet
restore. Meanwhile, since the subject can not be described as a node degree, pruning can be based on this, whennodes[i] - nodes[child] == 1 && children[i] = 0
the time is not allocated, as allocated in this way will of node i is 1, do not go down, pruning.At the same time pay attention to detail, according to the algorithm logically from start to finish with a
unfinishedParentSet
line, but we have a set of elements in the collection increase or decrease during traversal, Java'sforeach
traversal can not increase or decrease the elements (will throw an exception),iterator
traversal Elements cannot be added. Normal for traversing adding or subtracting elements will affect the semantics of the traversal (deleting an element may reduce the traversal to the element), so every time the code is allocated, it will rebuild a set that is the same as the original set and perform the new set Increase or decrease. Of course, you can also use one more field to record whether the node is deleted. This is related to the specific language implementation, and has nothing to do with the algorithm.The specific code is as follows.
Code
import java.util.*; public class Solution { // number of nodes public static int n; public static int[] nodes; // the number of the node i's children public static int[] children; public static void main(String[] args) { Scanner in = new Scanner(System.in); n = in.nextInt(); nodes = new int[n]; children = new int[n]; in.nextLine(); boolean canMakeTree = true; for (int i = 0; i < n; i++) { nodes[i] = in.nextInt(); if (nodes[i] == 2) canMakeTree = false; } Arrays.sort(nodes); // reverse for (int i = 0; i < n/2; i++) { int temp = nodes[i]; nodes[i] = nodes[n-1-i]; nodes[n-1-i] = temp; } if (nodes[0] != n) { canMakeTree = false; } if (!canMakeTree) { System.out.println("NO"); return; } Set<Integer> unfinishedParentSet = new HashSet<>(); for (int i = 0; i < n; i++) { if (nodes[i] > 1) unfinishedParentSet.add(i); } if (allocateNode(1, unfinishedParentSet)) { System.out.println("YES"); } else { System.out.println("NO"); } } public static boolean allocateNode(int index, Set<Integer> unfinishedParentSet) { Set<Integer> newSet = new HashSet<>(unfinishedParentSet); if (index == n) { if (unfinishedParentSet.size() != 0) return false; for (int i : children) { if (i == 1) return false; } return true; } for (int parentIndex : unfinishedParentSet) { if (nodes[parentIndex] > nodes[index]) { if (nodes[parentIndex] == nodes[index] + 1 && children[parentIndex] == 0) { continue; } // try to allocate nodes[parentIndex] -= nodes[index]; if (nodes[parentIndex] == 1) newSet.remove(parentIndex); children[parentIndex]++; // succeed if (allocateNode(index + 1, newSet)) return true; // fail to allocate if (nodes[parentIndex] == 1) newSet.add(parentIndex); nodes[parentIndex] += nodes[index]; children[parentIndex]--; } } return false; } }