I am having difficulties coding this and was wondering if someone can help me code this program.
If someone can help me get started then that'd be great. Thank you.
Also I was wondering what sections that I need topics I need to study for this because I am trying to code and having a really difficult time coding this. I know, strange, because I havent had this difficulty since I started CS first.
//Homework: revise this file, see TODO items below.
//Given a maze of size N, the method findPath(maze) finds an open
//path from (0,0) to (N-1,N-1), if such a path exists.
//
//See main() comments for its command line usage.
//TODO: the current solution is recursive (dfs() calls itself). You
//need to make it non-recursive. One way is to use an explicit stack
//instead of the runtime stack. You do not need to find exactly the
//same open paths as found by the given code.
//TODO(EC): modify findPath so it finds a *shortest* open path from
//(0,0) to (N-1,N-1), when one exists. You can read about a method
//for this, "breadth first search", in Section 4.1 of your book.
//TODO(EC): define the method findWallPath. Whenever findPath fails to
//find a path, there should be a "blocking" path of walls. This path
//can start at any wall on the top or right sides of the maze, and
//end at any wall at the bottom or left sides of the maze. Two walls
//can be adjacent by a cardinal OR diagonal step. Again, recursion
//is not allowed. Finding a wall path is good, shortest is better.
//For grading, we ignore the main() method, so do what you like with
//that. We only test your findPath and findWallPath methods.
public class PathFinder
{
// Any data fields here should be private and static. They exist
// only as a convenient way to share search context between your
// static methods here. It should be possible to call your
// findPath() method more than once, on different mazes, and
// to get valid results for each maze.
// The maze we are currently searching.
private static Maze m;
// GOAL: for each reachable open position p, parent[p.i][p.j]
// should be an open position that is closer to the start position
// S. These parent links should form a tree, rooted at S.
private static Position[][] parent;
public static Deque<Position> findPath(Maze maze)
{
m = maze; // save the maze
int N = m.size(); // the maze is N by N
parent = new Position[N][N]; // initially all null
Position S = new Position(0,0); // start of search
Position T = new Position(N-1,N-1); // goal of search
// Compute parent for each position reachable from S.
// Since S is the root, we will let S be its own parent.
// Compute parent links, by recursive depth-first-search!
dfs(S, S);
// If T has no parent, it is not reachable, so no path.
if (parent[T.i][T.j]==null)
return null;
// Otherwise, we can reconstruct a path from S to T.
LinkedDeque<Position> path = new LinkedDeque<Position>();
for (Position u=T; !u.equals(S); u=parent[u.i][u.j])
path.addFirst(u);
path.addFirst(S);
return path;
}
// depth-first-search: set parent for each reachable p.
private static void dfs(Position p, Position from)
{
if (!m.inRange(p) || !m.isOpen(p) || parent[p.i][p.j] != null)
return;
// System.out.println("found " + p + " via parent " + from);
parent[p.i][p.j] = from;
// Now recursively try the four neighbors of p.
for (int dir=0; dir<4; ++dir)
dfs(p.neighbor(dir), p);
}
// This method is entirely up to you.
public static Deque<Position> findWallPath(Maze maze) { return null; }
// Usage:
// java PathFinder MAZEFILE
// Reads maze, finds path, prints maze with path.
public static void main(String[] args)
throws java.io.IOException
{
Maze m = new Maze(args[0]);
System.out.println(m);
Deque<Position> path = findPath(m);
if (path==null) {
System.out.println("No path found");
return;
}
System.out.println("Found path of " +
path.size() +
" positions");
System.out.println(path);
char[][] map = m.copyArray();
// Mark the path with X's
for (Position p: path)
{
assert map[p.i][p.j] == '0';
map[p.i][p.j] = 'X';
}
// Now print the marked map.
System.out.println(Maze.toString(map));
}
// Java "best practice": this class is all static, so we should
// never instantiate it. To enforce that, we make its default
// constructor private.
private PathFinder() {}
}
The simplest approach to this problem would be to translate the maze (if it isn't yet) into a graph and afterwards implement either in-depth or breadth-first search that searches for the exit of the maze. And btw. you shouldn't write anything about homework in your post.
Related
I have a problem requiring me to implement an algorithm finding path from a character to another character with obstacles along the way.
I know there are a lot of advanced pathfinding algorithms(A*, BFS, DFS,dijkstra....). However, I am struggling to implement all these concepts in my code after plenty of research and attempts, and also I don't think I am required to implement all these advanced algorithms.
"Shortest" path is not the requirement, and all I need is a path that can lead my character to another character by avoiding moving onto obstacles.
Can anyone give me an idea (maybe some algorithms better than backtracking)or useful website (similar examples) for this problem?
Any help would be much appreciated
I can recommend you the A* algortihm.
Its easy to implements the algorithm. For my A* i used the wikipedia code and the geekforgeek code.
I'll post my code aswell its in C# but very similiar to java:
public List<ANote> findPath(ANote start, ANote end)
{
if (start == null || end == null || start == end || !start.walkable || !end.walkable)
return null;
List<ANote> openSet = new List<ANote>();
List<ANote> closedSet = new List<ANote>();
start.parent = null;
openSet.Add(start);
start.h = getDistance(start, end);
while (openSet.Any())
{
openSet = openSet.OrderBy(o => o.f).ToList();
ANote current = openSet[0];
if (current == end)
break;
openSet.Remove(current);
closedSet.Add(current);
foreach (ANote neighbor in current.adjacted)
{
if (closedSet.Contains(neighbor))
continue;
double _gScore = current.g + 1; // For me every distance was 1
if (openSet.Contains(neighbor) && _gScore >= neighbor.g)
continue;
if (!openSet.Contains(neighbor))
openSet.Add(neighbor);
neighbor.parent = current;
neighbor.g = _gScore;
neighbor.h = getDistance(neighbor, end);
}
}
return reconstructPath(start, end);
}
private List<ANote> reconstructPath(ANote start, ANote end)
{
List<ANote> backNotes = new List<ANote>();
ANote current = end;
while (current.parent != null)
{
backNotes.Add(current);
current = current.parent;
}
return backNotes;
}
public class ANote
{
public ANote parent { get; set; }
public double f { get { return g + h; } }
public double g { get; set; }
public double h { get; set; }
public int x { get; set; }
public int y { get; set; }
public bool walkable { get; set; }
public List<ANote> adjacted { get; set; } = new List<ANote>();
public ANote(int x, int y)
{
this.x = x;
this.y = y;
walkable = true;
}
}
Important for this code is that you must define the adjacted nodes and which are walkable and what are not before you search.
I hope my code can help you to implement A* in your code.
Since I have no idea how your "Grid" is described, and what "Cell" is, I assume the grid is rectangular, the cells only map the objects on it, not the empty spaces.
I suggest you make an char[][] array = new char[rows][columns]; (or char) initialize it with some value and iterate over Cells, fill the 2D array in some meaningful manner, the example is G for goal, # for obstacle, etc. Then you start a DFS from Goal to look for Start.
You need to store the correct path somewhere, so you need a ArrayList list; variable too. Since it's a list, you can add items to it with list.add(item);, which is handy.
Non-optimal path: DFS
DFS is a really basic recursive algorithm, in your case it will go like this:
bool DFS(list, array, row, column):
if(array[row][column] == '#' or
array[row][column] == 'v') return False; # Obstacle or visited, ignore it
if( ... == 'S') return True; # It's the Start, path found
array[row][column] = 'v'; # mark as visited, nothing interesting.
# If you want the shortest path, you're supposed to put here the distance from goal,
#that you would pass on and increment as additional argument of DFS
#Check for edge cases, or initialize array to be bigger and place obstacles on edge#
if( DFS(list, array, row-1, column) ){ # If DFS fount a path to Start from cell above
list.add("Move Up"); # Then you add a direction to go below to the list
return True; # And then tell the previous DFS, that the path was found
}
if()
if()
if()
# And then you add the checks for the other directions in a similar manner
return False; # You didn't find anything anywhere
}
That is not the code, but it should be enough for you to do your assignement from there.
Chances are it'll find a path like this:
...→→→→↓
...↑.↓←↓
...S.F↑↓
......↑↓
......↑←
But in grids with a lot of obstacles or only one correct path it'll make more reasonable paths. Also you can improve it by selecting the order you try directions in so it always tries to go towards Goal first, but that's a pain.
Optimal path: augmented DFS
To find the shortest path usually people refer to A*, but I read up on it and it's not as I remember it and it's just unnecessarily complicated, so I'll explain an expanded DFS. It takes a little longer to find the answer, than A* or BFS would, but for reasonably-sized grids it's not noticeable.
The idea of the algorithm is to map the entire grid with distances to Goal and then walk from start to goal following decreasing distance.
First you will need to use int[][] array instead of char of the previous case. That is because you need to store distances, which char can too to some extent, but also non-distance markers in the grid, like obstacles and such.
The idea of the algorithm is you call DFS(array, row, col, distance), where distance is calculated as distance of the Cell that calls DFS incremented by 1. Then DFS in the next cell checks if the distance it was passed is smaller than its current distance, if it is so, then there was a shorter path found to that cell and you need to recalculate all its neighbors too. Otherwise the new path is longer and you can disregard it. By calling DFS recursively you will gradually map the entire maze.
After that you will call another function FindPath(list, array, row, col), that will check the Cell it started in and add a direction to the cell with neighbor.distance == (this.distance - 1) to the list and then call FindPath on that neighbor until distance is 0, at which point it's the goal.
It should look smth like this:
main()
{
# initialize grid with Integer.MAX_VALUE or just a big enough number
# for Cell in Cells -> put obstacles on Grid as -1,
# find the Start and Goal and record them somewhere
# DFS_plus(array, Goal, 0);
# FindPath(list, array, Start);
# Done
}
void DFS_plus(array, row, column, distance):
if(array[row][col] <= distance) return; # There already exists a shorter path there
# or it's an obstacle, we store obstacles as -1.
# It's smaller than any possible path and thus blocks further search
array[row][column] = distance; # update distance.
# If this happened its neighbors will need to be updated too.
#Check for edge cases, or initialize array to be bigger and place obstacles on edge#
DFS_plus(array, row-1, column, distance+1); # You just map everything, no returns expected
DFS_plus(); # For all 4 directions
DFS_plus();
DFS_plus();
}
FindPath(list, array, row, col){
if(array[row][col] == 0) return; # It's the Goal
if(array[row-1][col] == (array[row][col] - 1)){ # Check if Cell above is 1 closer to Goal
list.add("MoveUp"); # Add direction
FindPath(list, array, row-1, col); # Look for next direction
return; # You don't need to check other directions as path is guaranteed
}
if(){}; # Check other directions if Up wasn't the one
if(){};
if(){};
}
It is not much more complicated, but it gets you the shortest path. It's not the quickest way to find the shortest path, but it's relatively simple as any recursive algoithm.
I try to write a MinMax program in Java for connect-four game, but this program should also be applicable to other games. But, I encountered a problem, which I cannot pass for few days. The values for nodes are not set properly. I am sharing my piece of code which is responsible for generating a tree.
Maybe you will notice where I made a mistake.
If anyone could help me with this, I will be very happy.
public Node generateTree(Board board, int depth) {
Node rootNode = new Node(board);
generateSubtree(rootNode, depth);
minMax(rootNode, depth);
return rootNode;
}
private void generateSubtree(Node subRootNode, int depth) {
Board board = subRootNode.getBoard();
if (depth == 0) {
subRootNode.setValue(board.evaluateBoard());
return;
}
for (Move move : board.generateMoves()) {
Board tempBoard = board.makeMove(move);
Node tempNode = new Node(tempBoard);
subRootNode.addChild(tempNode);
generateSubtree(tempNode, depth - 1);
}
}
public void minMax(Node rootNode, int depth) {
maxMove(rootNode, depth);
}
public int maxMove(Node node, int depth) {
if (depth == 0) {
return node.getValue();
}
int bestValue = Integer.MIN_VALUE;
for (Node childNode : node.getChildren()) {
int tempValue = minMove(childNode, depth - 1);
childNode.setValue(tempValue);
if (tempValue > bestValue) {
bestValue = tempValue;
}
}
return bestValue;
}
public int minMove(Node node, int depth) {
if (depth == 0) {
return node.getValue();
}
int bestValue = Integer.MAX_VALUE;
for (Node childNode : node.getChildren()) {
int tempValue = maxMove(childNode, depth - 1);
childNode.setValue(tempValue);
if (tempValue < bestValue) {
bestValue = tempValue;
}
}
return bestValue;
}
Board class is the representation of the board state.
Move class hold the move to perform (integer [0-8] for tic-tac-toe, [0-6] for Connect Four).
Node class holds the Move and value how good given move is. Also, holds all its children.
In the code I use this method like this:
Node newNode = minmax.generateTree(board, depth, board.getPlayer());
Move newMove = new TicTacToeMove(board.getPlayer(), newNode.getBestMove().getMove(), depth);
board = board.makeMove(newMove);
And when it's obvious that given move is a losing move (or winning), I do not receive this move.
Alright, you did make a couple of mistakes. About 3-4, depending on how you count ;) Took me a bit of debugging to figure it all out, but I finally got an answer for you :D
Mistake #1: All your parents always get twins (that poor mother)
This is only the case with the code you uploaded, not the code in your question, so maybe we count it as half a mistake?
Since your trees aren't that big yet and it won't destroy your algorithm, this was the least important one anyway. Still, it's something to watch out for.
In your uploaded code, you do this in your generateSubtree method:
Node tempNode = new Node(tempBoard, move, subRootNode);
subRootNode.addChild(tempNode);
As that constructor already adds the child to the subRootNode, the second line always adds it a second time.
Mistake #2: That darn depth
If you haven't reached your desired depth yet, but the game is already decided, you completely ignore that. So in your provided example that won't work, if - for example - you look at making move 7 instead of 3 (which would be the 'right' move) and then the opponent does move 3, you don't count it as -10 points because you haven't reached your depth yet. It still won't get any children, so even in your minmax, it will never realize it's a screwed up way to go.
Which is why every move is 'possible' in this scenario and you just get the first one returned.
In the previous moves, there was luckily always a way to reach a losing move with your opponents third move (aka move #5), which is why those were called correctly.
Alright, so how do we fix it?
private void generateSubtree(Node subRootNode, int depth, int player) {
Board board = subRootNode.getBoard();
List<Move> moveList = board.generateMoves();
if (depth == 0 || moveList.isEmpty()) {
subRootNode.setValue(board.evaluateBoard(player));
return;
}
for (Move move : moveList) {
Board tempBoard = board.makeMove(move);
Node tempNode = new Node(tempBoard, move, subRootNode);
generateSubtree(tempNode, depth - 1, player);
}
}
Just get the move list beforehand and then look if it's empty (your generateMoves() method of the Board class (thank god you provided that by the way ;)) already checks if the game is over, so if it is, there won't be any moves generated. Perfect time to check the score).
Mistake #3: That darn depth again
Didn't we just go over this?
Sadly, your Min Max algorithm itself has the same problem. It will only even look at your values if you have reached the desired depth. You need to change that.
However, this is a bit more complicated, since you don't have a nice little method that already checks if the game is finished for you.
You could check to see if your value was set, but here's the problem: It might be set to 0 and you need to take that into account as well (so you can't just do if (node.getValue() != 0)).
I just set the initial value of each node to -1 instead and did a check against -1. It's not... you know... pretty. But it works.
public class Node {
private Board board;
private Move move;
private Node parent;
private List<Node> children = new ArrayList<Node>();;
private boolean isRootNode = false;
private int value = -1;
...
And this in the maxMove:
public int maxMove(Node node, int depth) {
if (depth == 0 || node.getValue() != -1) {
return node.getValue();
}
int bestValue = Integer.MIN_VALUE;
for (Node childNode : node.getChildren()) {
int tempValue = minMove(childNode, depth - 1);
childNode.setValue(tempValue);
if (tempValue > bestValue) {
bestValue = tempValue;
}
}
return bestValue;
}
It works the same for minMove of course.
Mistake #4: The player is screwing with you
Once I changed all that, it took me a moment with the debugger to realize why it still wouldn't work.
This last mistake was not in the code you provided in the question btw. Shame on you! ;)
Turns out it was this wonderful piece of code in your TicTacToeBoard class:
#Override
public int getPlayer() {
// TODO Auto-generated method stub
return 0;
}
And since you called
MinMax minmax = new MinMax();
Node newNode = minmax.generateTree(board, (Integer) spinner.getValue(), board.getPlayer());
in your makeMove method of TicTacToeMainWindow, you would always start out with the wrong player.
As you can probably guess yourself, you just need to change it to:
public int getPlayer() {
return this.player;
}
And it should do the trick.
Also:
Just a couple of things I'd like to remark at this point:
Clean up your imports! Your TicTacToe actually still imports your ConnectFour classes! And for no reason.
Your board is rotated and mirrored in your board array. WHY? You know how annoying that is to debug? I mean, I guess you probably do :D Also, if you're having problems with your code and you need to debug it's extremely helpful to overwrite your boards toString() method, because that will give you a very nice and easy way to look at your board in the debugger. You can even use it to rotate it again, so you see don't have to look at it lying on the side ;)
While we're at the subject of the board... this is just me but... I always tried clicking on the painted surface first and then had to remember: Oh yeah, there were buttons :D I mean... why not just put the images on the buttons or implement a MouseListener so you can actually just click on the painted surface?
When providing code and/or example images, please take out your test outputs. I'm talking about the Player 1 won!s of course ;)
Please learn what a complete, verifiable and minimal example is for the next time you ask a question on StackOverflow. The one in your question wasn't complete or verifiable and the one you provided on github was... well... not complete (the images were missing), but complete enough. It was also verifiable, but it was NOT minimal. You will get answers a LOT sooner if you follow the guidelines.
Here is the revised code, the other classes don't matter I hope. If you need the other classes, tell me and I'll add it. When I run this I get the naming error when I try to retrieve the spaces that are possible to move in.
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Space> openlist = new ArrayList<Space>();
int g = 0;
Bot Dave = new Bot("Dave");
Goal goal = new Goal();
Obstacle first = new Obstacle("First");
int numofobst = 1;
Space right = new Space(Dave.getX()+1, Dave.getY());
Space left = new Space(Dave.getX()-1, Dave.getY());
Space up = new Space(Dave.getX(), Dave.getY()+1);
Space down = new Space(Dave.getX(), Dave.getY()-1);
int openpossible= 0;
//now its creating an array of each space and getting the fs of each one.
/*time to check which spaces are possible for the bot to move. if they are possible add the space to a possible array list.
* then we check to see which f is smaller by addign a min value.
* we then sort it and get the first space.
* we move to that space.
*/
if (Dave.checkob(first, right, numofobst) == right){
openlist.add(right);
}
if (Dave.checkob(first, left, numofobst) == left){
openlist.add(left);
}
if (Dave.checkob(first, up, numofobst) == up){
openlist.add(up);}
if (Dave.checkob(first, down, numofobst) == down){
openlist.add(down);}
for (int i = 0; i < openlist.size(); i++){
System.out.println("Space available is" + openlist.get(i));
}
System.out.println("Space available is" + openlist);
}
You're code is missing a lot of things (mostly everything).
First try to implement a simple Dijkstra. Do the one in O(V^2), then upgrade it to O(ElogV). It's a bit slower than A* but a lot simpler to understand. Once you get it you can upgrade it to A* by changing a few lines of code.
I'm writing an app for a family member who is a teacher. She asked for an app to allow her to enter a bunch of kids, set their handedness, set who they can't sit next to, specify how many seats per bench, and then generate a random layout for the kids such that no left-handers sit to the right of a right-hander, and the kids that shouldn't sit next to each other are not adjacent on a bench.
This isn't quite the same problem as a generic table seating algorithm because there are 2 ends to a bench, and because there is no "value" to the nodes to create any preferential groupings.
I decided to create a directed graph where the edges represent who can sit to the right of a given kid. Then I do a recursive DFS from every node without touching a node twice until I get a path where every node has been touched. One catch is that at the "end" of every bench, anyone can sit to their "right".
This algorithm seems to always work, which is nice. But the runtime seems to grow awfully once I get beyond say 10 kids on a single bench assuming the benches can seat say 20 kids. Am I doing something wrong, or is there some much better way to solve this? Java code follows.
Edit: Sorry I didn't make this clear, but I want to achieve a RANDOM seating arrangement each time, such that the kids don't get stuck in the same place or on the same bench or next to the same kids. Also I've got my app running against this algorithm here:
http://kcraigie.com/sittychart
Currently I'm enforcing an upper limit of 1,000,000 node touches so that my server doesn't get hosed. You can see that the algorithm seems to scale properly until you set the seats per bench to 9 or so at which point it immediately becomes unwieldy.
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;
}
I think you don't need to generate a list of possible left Nodes for each node. Instead, do it on the fly in an recursive algorithm with trackback.
On the first seat you seat the first node. Search through the list of nodes for the first possible neighbour and seat him there. Repeat until the plan is complete or you reach a dead end. In that case, go back one seat and seat the next possible person there (eg. if it was Node 4 change it to Node 5). Either try the next seat from there or, if not possible to find a next Node (e.g. the node there was already the last on the list) go back one step until there is a next node.
With this method, you should statistically have to compute n!/2 possibilities for a number of students n to find an answer.
PS: I hope you understand my descrition of the algorithm. If i had more time i would have made a diagram.
I wouldn't automatically think graphs for this sort of problem. Building the graph gives a complexity of O(n^2), and a DFS is O(V+E) (with V being verticies, E being edges, which will be less than O(n^2), so you're still looking at O(n^2)).
If no left hander can be directly to the right of a right hander, then for a single bench, there's no way to order the kids so that any right hander is to the right at all of any left hander. So your result is always going to look something like:
l l l l l r r r r r
You can prove this by induction. If the correct solution has a right hander anywhere to the left of a left hander, i.e :
r ? l
Then there must be a kid '?' who is either left or right handed that doesn't break the rule. If the kid is right handed, it breaks it for the first left handed kid. If the kid is left handed, it breaks the rule for that kid.
So, what you need to do is sort your left and right handed kids, and look at who can and can't sit next to each other. In reality, if the kids relationships aren't like an episode of the bold and the beautiful, and you don't have a crazy graph of who can and can't sit next to each other, you could probably use a greedy algorithm. You would just start from the list of left handers, pulling out one kid at a time. If they won't sit next to the last one, then pull out the next, and try again. This would give you a complexity of O(n), but you might not get a solution everytime.
Alternatively, you could use a recursive algorithm to put together compatible groups of kids one pair at a time, and build up a solution that way. This would obviously be a more complex algorithm, but you'd always get an answer.
If you've got more than one bench though, then this won't work at all.
I recently gave an interview and was asked the following question.
A maze is a group of linked Places. Each Place has a North, South, East, and West Place adjacent to it. There are two special pre-defined Place's: Place Wall represents a wall - the mouse can't go there. Place Cheese is ... cheese! The connections between Places are symmetrical - if you start from any Place and go North and then South, you return to where you were.
To simplify things, the maze has no closed loops - that is, if you start in any Place and follow any path, you eventually either hit a wall or find cheese - you never come back to the Place you started unless you actually retrace your steps.
A mouse starts off in some Place and searches around for Cheese. When it finds Cheese, it returns a set of directions - a string of the letters NSEW that lead from where it started to the Cheese.
The following framework defines the classes and functions. Some other code not included here generates a maze by creating a bunch of Place's and linking them. It then calls mouse(), passing some starting Place from the maze:
interface Place {
// Return the adjacent Place in the given direction
public Place goNorth();
public Place goSouth();
public Place goEast();
public Place goWest();
// Returns true only for the special "Wall" place
public bool isWall();
// Returns true only for the special "Cheese" place
public bool isCheese();
};
class Mouse {
public Mouse() {}
// Return a string of the letters NSEW which, if used to traverse the
// the maze from startingPoint, will reach a Place where isCheese() is
// true. Return null if you can't find such a path.
public String findCheese(Place startingPoint) {
... fill this in ...
}
}
Implement findCheese(). You can add any fields or helper methods you need to Mouse.
Extra credit: Eliminate the "no closed loops" restriction. That is, change your code so that it works correctly even if there might be a path like SSNEEW that leads the mouse back to the Place it started from.
This is what I tried. I understand this won't be the best or optimized solution, and wanted feedback as to what I else I could try. I have not considered the extra credit part
public String findCheese(place startingPoint)
{
//Call helper function in all 4 directions;
return findCheeseHelper(startingPoint,new StringBuilder("N")).append(
findCheeseHelper(startingPoint,new StringBuilder("S"))).append(
findCheeseHelper(startingPoint,new StringBuilder("E"))).append(
findCheeseHelper(startingPoint,new StringBuilder("W"))).toString();
}
public StringBuilder findCheeseHelper(place startingPoint, StringBuilder direction)
{
StringBuilder nDir=new StringBuilder("");
StringBuilder sDir=new StringBuilder("");
StringBuilder eDir=new StringBuilder("");
StringBuilder wDir=new StringBuilder("");
//Rerturn which direction this step came from if cheese found
if(startingPoint.isCheese())
{
return direction;
}
//Specify this is not a correct direction by returning an empty String
else if(startingPoint.isWall())
{
return "";
}
//Explore all other 3 directions (except the one this step came from)
if(direction=="N")
{
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("N"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("E"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("W"));
}
else if(direction=="E")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("N"));
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("S"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("E"));
}
else if(direction=="W")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("N"));
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("S"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("W"));
}
else if(direction=="S")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("S"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("E"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("W"));
}
//If I hit wall in every direction, I will get empty string and so specify to calling
//function that this is not a correct direction
if(nDir.equals("") && sDir.equals("") && eDir.equals("") && wDir.equals(""))
return new StringBuilder("");
//If Cheese was found in even 1 direction, return direction to come to this step, appended with the path
// forward to the calling function
return direction.append(nDir).append(sDir).append(eDir).append(wDir);
}