The most efficient bench bench seating algorithm?

I am writing an application for a family member who is a teacher. She asked for an application to let her enter a bunch of children, establish their routine, establish who they cannot sit next to, indicate how many seats are on the bench, and then create a random pattern for the children, people are sitting to the right of the right-hander, and the children who should not sit next to each other, not adjacent to the bench.

This is not the same problem as the general table placement algorithm, because there are two ends of the bench and because the nodes do not have a β€œvalue” to create any preferred groupings.

I decided to create a directed graph where the ribs represent who can sit to the right of this child. Then I do recursive DFS from each node, without touching the node twice, until I get the path to which each node was affected. One catch is that at the "end" of each bench, everyone can sit until their "right."

This algorithm always works, which is nice. But the work time seems to be growing terribly as soon as I go beyond, say, 10 children on one bench, suggesting that the benches can sit, say 20 children. Am I doing something wrong, or is there some better way to solve this? The following is the Java code.

Edit: Sorry, I did not clarify this, but I want to have to install RANDOM every time so that the children do not get stuck in the same place or on the same bench or next to the same children. Also my application works against this algorithm:

http://kcraigie.com/sittychart

I am currently applying an upper limit of 1,000,000 node to prevent my server from accessing. You can see that the algorithm seems to scale properly, until you set the bench space to 9 or so, after which it immediately becomes cumbersome.

private static class Person { private String m_name = null; private Handedness m_handedness = null; private Set<Person> m_nonadjacents = null; } private static class Node { private Person m_person = null; private List<Node> m_possibleRightNodes = null; private boolean m_isInPath = false; } private Stack<Node> generateSeatingArrangement() { // Generate randomized directed graph, start with all nodes as root nodes for(Person leftPerson: people.values()) { Node node = new Node(leftPerson); nodes.put(leftPerson, node); } // Create all edges based on constraints for(Node leftNode: nodes.values()) { List<Node> possibleRightNodes = new LinkedList<>(); for(Node rightNode: nodes.values()) { Person leftPerson = leftNode.getPerson(); Person rightPerson = rightNode.getPerson(); if(leftNode==rightNode) { log.fine("Can't seat '" + leftPerson.getName() + "' next to himself"); continue; } if(leftPerson.getHandedness()==Person.Handedness.RIGHT_HANDED && rightPerson.getHandedness()==Person.Handedness.LEFT_HANDED) { log.fine("Can't seat right-handed '" + leftPerson.getName() + "' to the left of left-handed '" + rightPerson.getName() + "'"); continue; } if(leftPerson.getNonadjacents().contains(rightPerson)) { log.fine("Can't seat '" + leftPerson.getName() + "' next to '" + rightPerson.getName() + "'"); continue; } if(rightPerson.getNonadjacents().contains(leftPerson)) { // TODO: This should be redundant but not enforcing right now... log.fine("Can't seat '" + rightPerson.getName() + "' next to '" + leftPerson.getName() + "'"); continue; } log.fine("Can seat '" + leftPerson.getName() + "' to the left of '" + rightPerson.getName() + "'"); possibleRightNodes.add(rightNode); } Collections.shuffle(possibleRightNodes); leftNode.setPossibleRightNodes(possibleRightNodes); } List<Node> nodes2 = new LinkedList<>(nodes.values()); Collections.shuffle(nodes2); // Perform recursive graph traversal Stack<Node> pathStack = new Stack<>(); for(Node node: nodes2) { TraversalStatistics stats = new TraversalStatistics(); boolean isPathFound = depthFirstSearchRecur(numSeatsPerBench, nodes2, pathStack, node, stats); if(isPathFound) { break; } pathStack.clear(); } } // The resursive DFS method private boolean depthFirstSearchRecur(int numSeatsPerBench, List<Node> allNodes, Stack<Node> pathStack, Node node, TraversalStatistics stats) { stats.numNodesTouched++; if(node.isInPath()) { stats.numLeavesReached++; return false; } pathStack.push(node); node.setIsInPath(true); if(pathStack.size() >= allNodes.size()) { return true; // We win! } if(pathStack.size() % numSeatsPerBench == 0) { // "End" of a bench, anyone can "sit to the right of" me for(Node node2: allNodes) { if(node == node2) { // Can't sit next to myself continue; } if(depthFirstSearchRecur(numSeatsPerBench, allNodes, pathStack, node2, stats)) { return true; } } } else { for(Node node2: node.getPossibleRightNodes()) { if(depthFirstSearchRecur(numSeatsPerBench, allNodes, pathStack, node2, stats)) { return true; } } } pathStack.pop(); node.setIsInPath(false); return false; } 
+5
source share
2 answers

I think you do not need to create a list of possible left nodes for each node. Instead, do it on the fly in a recursive trackback algorithm.

In the first place you sit the first node. Search the list of nodes for the first possible neighbor and put him there. Repeat until the plan is completed or you will reach a dead end. In this case, return to one place and place the next possible person there (for example, if he was Node 4, replace him with Node 5). Or try the next place from there, or if you can’t find the next Node (for example, Node was already the last in the list), go back one step until the next node appears.

Using this method, you must statistically calculate n! / 2 opportunities for multiple students n to find the answer.

PS: I hope you understand my description of the algorithm. If I had more time, I would make a chart.

+1
source

I would not automatically read the graphs for this kind of problem. Plotting gives complexity O (n ^ 2), and DFS gives O (V + E) (with V being vertices, E being edges that are smaller than O (n ^ 2), so you're still looking at O (n ^ 2)).

If a lefty cannot be right to the right of his right hand, then for one bench there is no way to order children so that any right-hander is on the right of all left-handed people. Therefore, your result will always look something like this:

 lllllrrrrr 

You can prove it by induction. If the correct solution has a right hand to the left of the left hand, that is:

 r ? l 

Then there must be a child? which is either left or right, which does not violate the rules. If the child is right, he breaks it for the first left baby. If the child is left-handed, he breaks the rule for this child.

So what you need to do is sort your left and right children and see who can and cannot sit next to each other. In fact, if the relationship of the children is not like an episode of the bold and beautiful, and you do not have a crazy schedule of someone who can and cannot sit next to each other, you can probably use the greedy algorithm. You would only start from the list of lefties by pulling one child at a time. If they will not sit next to the latter, then pull out the next one and try again. This will give you O (n) complexity, but you will not be able to get a solution every time.

Alternatively, you can use the recursive algorithm to combine compatible groups of children one pair at a time, and thus create a solution. Obviously, this will be a more complex algorithm, but you will always get the answer.

If you have more than one bench, then this will not work at all.

+1
source

Source: https://habr.com/ru/post/1234723/


All Articles