Meituan Written Test (2020-9-6) Staff Assignment

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:

  1. Everyone either has no subordinates or at least 2 direct reports
  2. I-affiliated individuals (including myself) have aia

Note: 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.

Insert picture description here

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) have ainodes. So for this root node of the tree, it represents the number of nodes in the entire tree, so the biggest aiis the root node, and if this constitutes a tree, the largest ainecessarily equal to n. The maximum can be aiperformed if a pre-determined equal to n.

Combined with claim 1 and claim 2, find aiif the value is equal to 2, it must not constitute such a tree, since aia 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

    nodesRecording the input array aivalues. First, nodesin descending order, it nodes[0]is the root of the tree, in addition to nodes[0]all have the parent node. Here the nodesvalues in the array assigned as the number of nodes required, such as nodes[i] = 6representative of the subtree rooted at the node needed allocate 5 (own count 1) nodes; when nodes[i] = 1Representative redistribution does not require a child of that node.

  • children Array

    Record the number of children of each node, which is used to finally determine whether the degree of each node is not 1.

  • unfinishedParentSet set

    This set represents need to set the child node's parent node assigned index, i.e., nodes[i] > 1all 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 aiequal to 2, the representative does not constitute such a tree, after the input is completed, to nodesbe sorted in descending order, if nodes[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 nodesthe array, the nodesarray index is greater than 1 is added unfinishedParentSet. Then perform depth-first traversal and backtracking.

Insert picture description here

As shown, the nodeselement of the array nodes[1]( nodes[0]the root node, has no parent node) attempts to allocate to start unfinishedParentSetin the parent node, the parent FIG x nodes are unfinishedParentSetin 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]the children[i]plus 1, and if nodes[i]the parent node is equal to 1 representing the assignment is completed, the unfinishedParentSetdeleting. If the attempt to allocate fails to backtrack, will nodes, childrenand unfinishedParentSetrestore. Meanwhile, since the subject can not be described as a node degree, pruning can be based on this, when nodes[i] - nodes[child] == 1 && children[i] = 0the 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 unfinishedParentSetline, but we have a set of elements in the collection increase or decrease during traversal, Java's foreachtraversal can not increase or decrease the elements (will throw an exception), iteratortraversal 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;
    }
}

reference

Guess you like

Origin blog.csdn.net/qq_41512783/article/details/109790001