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; }