In an attempt to write a brute force maze solving C program, I've written this java program first to test an idea. I'm very new to C and intend to convert it after getting this right in java. As a result, I'm trying stick away from arraylists, fancy libraries, and such to make it easier to convert to C. The program needs to generate a single width path of shortest steps to solve a maze. I think my problem may be in fragmenting a path-storing array passed through each recursion. Thanks for looking at this. -Joe
maze:
1 3 3 3 3
3 3 3 3 3
3 0 0 0 3
3 0 3 3 3
0 3 3 3 2
Same maze solved by this program:
4 4 4 4 4
4 4 4 4 4
4 0 0 0 4
3 0 3 3 4
0 3 3 3 2
number notation are explained in code
public class javamaze {
static storage[] best_path;
static int best_count;
static storage[] path;
//the maze - 1 = start; 2 = finish; 3 = open path
static int maze[][] = {{1, 3, 3, 3, 3},
{3, 3, 3, 3, 3},
{0, 0, 0, 0, 3},
{0, 0, 3, 3, 3},
{3, 3, 3, 3, 2}};
public static void main(String[] args) {
int count1;
int count2;
//declares variables used in the solve method
best_count = 0;
storage[] path = new storage[10000];
best_path = new storage[10000];
int path_count = 0;
System.out.println("Here is the maze:");
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
System.out.print(maze[count1][count2] + " ");
}
System.out.println("");
}
//solves the maze
solve(findStart()/5, findStart()%5, path, path_count);
//assigns an int 4 path to the maze to visually represent the shortest path
for(int count = 0; count <= best_path.length - 1; count++)
if (best_path[count] != null)
maze[best_path[count].getx()][best_path[count].gety()] = 4;
System.out.print("Here is the solved maze\n");
//prints the solved maze
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++){
System.out.print(maze[count1][count2] + " ");
}
System.out.print("\n");
}
}
//finds maze start marked by int 1 - this works perfectly and isn't related to the problem
public static int findStart() {
int count1, count2;
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
if (maze[count1][count2] == 1)
return (count1 * 5 + count2);
}
}
return -1;
}
//saves path coordinate values into a new array
public static void save_storage(storage[] old_storage) {
int count;
for(count = 0; count < old_storage.length; count++) {
best_path[count] = old_storage[count];
}
}
//solves the maze
public static Boolean solve(int x, int y, storage[] path, int path_count) {
//checks to see if grid squares are valid (3 = open path; 0 = wall
if (x < 0 || x > 4) { //array grid is a 5 by 5
//System.out.println("found row end returning false");
return false;
}
if (y < 0 || y > 4) {
//System.out.println("Found col end returning false");
return false;
}
//when finding finish - records the number of moves in static int best_count
if (maze[x][y] == 2) {
if (best_count == 0 || best_count > path_count) {
System.out.println("Found end with this many moves: " + path_count);
best_count = path_count;
save_storage(path); //copies path counting array into a new static array
}
}
//returns false if it hits a wall
if (maze[x][y] == 0)
return false;
//checks with previously crossed paths to prevent an unnecessary repeat in steps
for(storage i: path)
if (i != null)
if (i.getx() == x && i.gety() == y)
return false;
//saves current recursive x, y (row, col) coordinates into a storage object which is then added to an array.
//this array is supposed to fragment per each recursion which doesn't seem to - this may be the issue
storage storespoints = new storage(x, y);
path[path_count] = storespoints;
//recurses up, down, right, left
if (solve((x-1), y, path, path_count++) == true || solve((x+1), y, path, path_count++) == true ||
solve(x, (y+1), path, path_count++) == true || solve(x, (y-1), path, path_count++) == true) {
return true;
}
return false;
}
}
//stores (x, y) aka row, col coordinate points
class storage {
private int x;
private int y;
public storage(int x, int y) {
this.x = x;
this.y = y;
}
public int getx() {
return x;
}
public int gety() {
return y;
}
public String toString() {
return ("storage coordinate: " + x + ", " + y + "-------");
}
}
This wasn't originally intended to be an answer but it sort of evolved into one. Honestly, I think starting in Java and moving to C is a bad idea because the two languages are really nothing alike, and you won't be doing yourself any favors because you will run into serious issues porting it if you rely on any features java has that C doesn't (i.e. most of them)
That said, I'll sketch out some algorithmic C stuff.
Support Structures
typedef
struct Node
{
int x, y;
// x and y are array indices
}
Node;
typedef
struct Path
{
int maxlen, head;
Node * path;
// maxlen is size of path, head is the index of the current node
// path is the pointer to the node array
}
Path;
int node_compare(Node * n1, Node * n2); // returns true if nodes are equal, else false
void path_setup(Path * p, Node * n); // allocates Path.path and sets first node
void path_embiggen(Path * p); // use realloc to make path bigger in case it fills up
int path_toosmall(Path * p); // returns true if the path needs to be reallocated to add more nodes
Node * path_head(Path * p); // returns the head node of the path
void path_push(Path * p, Node * n); // pushes a new head node onto the path
void path_pop(Path * p); // pops a node from path
You might to change your maze format into an adjacency list sort of thing. You could store each node as a mask detailing which nodes you can travel to from the node.
Maze Format
const int // these constants indicate which directions of travel are possible from a node
N = (1 << 0), // travel NORTH from node is possible
S = (1 << 1), // travel SOUTH from node is possible
E = (1 << 2), // travel EAST from node is possible
W = (1 << 3), // travel WEST from node is possible
NUM_DIRECTIONS = 4; // number of directions (might not be 4. no reason it has to be)
const int
START = (1 << 4), // starting node
FINISH = (1 << 5); // finishing node
const int
MAZE_X = 4, // maze dimensions
MAZE_Y = 4;
int maze[MAZE_X][MAZE_Y] =
{
{E, S|E|W, S|E|W, S|W },
{S|FINISH, N|S, N|START, N|S },
{N|S, N|E, S|E|W, N|S|W },
{N|E, E|W, N|W, N }
};
Node start = {1, 2}; // position of start node
Node finish = {1, 0}; // position of end node
My maze is different from yours: the two formats don't quite map to each other 1:1. For example, your format allows finer movement, but mine allows one-way paths.
Note that your format explicitly positions walls. With my format, walls are conceptually located anywhere where a path is not possible. The maze I created has 3 horizontal walls and 5 vertical ones (and is also enclosed, i.e. there is a continuous wall surrounding the whole maze)
For your brute force traversal, I would use a depth first search. You can map flags to directions in a number of ways, like maybe the following. Since you are looping over each one anyway, access times are irrelevant so an array and not some sort of faster associative container will be sufficient.
Data Format to Offset Mappings
// map directions to array offsets
// format is [flag], [x offset], [y offset]
int mappings[][] =
{
{N, -1, 0},
{S, 1, 0},
{E, 0, 1},
{W, 0, -1}
}
Finally, your search. You could implement it iteratively or recursively. My example uses recursion.
Search Algorithm Pseudocode
int search_for_path(int ** maze, char ** visited, Path * path)
{
Node * head = path_head(path);
Node temp;
int i;
if (node_compare(head, &finish)) return 1; // found finish
if (visited[head->x][head->y]) return 0; // don't traverse again, that's pointless
visited[head->x][head->y] = 1;
if (path_toosmall(path)) path_embiggen(path);
for (i = 0; i < NUM_DIRECTIONS; ++i)
{
if (maze[head->x][head->y] & mappings[i][0]) // path in this direction
{
temp = {head->x + mappings[i][1], head->y + mappings[i][2]};
path_push(path, &temp);
if (search_for_path(maze, visited, path)) return 1; // something found end
path_pop(path);
}
}
return 0; // unable to find path from any unvisited neighbor
}
To call this function, you should set everything up like this:
Calling The Solver
// we already have the maze
// int maze[MAZE_X][MAZE_Y] = {...};
// make a visited list, set to all 0 (unvisited)
int visited[MAZE_X][MAZE_Y] =
{
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};
// setup the path
Path p;
path_setup(&p, &start);
if (search_for_path(maze, visited, &path))
{
// succeeded, path contains the list of nodes containing coordinates from start to end
}
else
{
// maze was impossible
}
It's worth noting that because I wrote this all in the edit box, I haven't tested any of it. It probably won't work on the first try and might take a little fiddling. For example, unless start and finish are declared globally, there will be a few issues. It would be better to pass the target node to the search function instead of using a global variable.
Related
I was looking into the Knight's Tour Problem, where the solution is obtained when a chess knight piece moves to every square on a grid exactly once. However, upon looking at different solutions for the problem, I keep seeing a specific array of numbers:
int xMove[] = { 2, 1, -1, -2, -2, -1, 1, 2 };
int yMove[] = { 1, 2, 2, 1, -1, -2, -2, -1 };
Where exactly these integers are coming from? Is there a way that you can solve the problem without these specific integers, or are they essential to the problem? For reference, here is the full code I was looking at. (credit GeeksforGeeks)
// Java program for Knight Tour problem
class KnightTour {
static int N = 8;
/* A utility function to check if i,j are
valid indexes for N*N chessboard */
static boolean isSafe(int x, int y, int sol[][])
{
return (x >= 0 && x < N && y >= 0 && y < N
&& sol[x][y] == -1);
}
/* A utility function to print solution
matrix sol[N][N] */
static void printSolution(int sol[][])
{
for (int x = 0; x < N; x++) {
for (int y = 0; y < N; y++)
System.out.print(sol[x][y] + " ");
System.out.println();
}
}
/* This function solves the Knight Tour problem
using Backtracking. This function mainly
uses solveKTUtil() to solve the problem. It
returns false if no complete tour is possible,
otherwise return true and prints the tour.
Please note that there may be more than one
solutions, this function prints one of the
feasible solutions. */
static boolean solveKT()
{
int sol[][] = new int[8][8];
/* Initialization of solution matrix */
for (int x = 0; x < N; x++)
for (int y = 0; y < N; y++)
sol[x][y] = -1;
/* xMove[] and yMove[] define next move of Knight.
xMove[] is for next value of x coordinate
yMove[] is for next value of y coordinate */
int xMove[] = { 2, 1, -1, -2, -2, -1, 1, 2 };
int yMove[] = { 1, 2, 2, 1, -1, -2, -2, -1 };
// Since the Knight is initially at the first block
sol[0][0] = 0;
/* Start from 0,0 and explore all tours using
solveKTUtil() */
if (!solveKTUtil(0, 0, 1, sol, xMove, yMove)) {
System.out.println("Solution does not exist");
return false;
}
else
printSolution(sol);
return true;
}
/* A recursive utility function to solve Knight
Tour problem */
static boolean solveKTUtil(int x, int y, int movei,
int sol[][], int xMove[],
int yMove[])
{
int k, next_x, next_y;
if (movei == N * N)
return true;
/* Try all next moves from the current coordinate
x, y */
for (k = 0; k < 8; k++) {
next_x = x + xMove[k];
next_y = y + yMove[k];
if (isSafe(next_x, next_y, sol)) {
sol[next_x][next_y] = movei;
if (solveKTUtil(next_x, next_y, movei + 1,
sol, xMove, yMove))
return true;
else
sol[next_x][next_y]
= -1; // backtracking
}
}
return false;
}
/* Driver Code */
public static void main(String args[])
{
// Function Call
solveKT();
}
}
// This code is contributed by Abhishek Shankhadhar
It's simply an exhaustive list of all the moves a knight can make, relative to its current position. That list is determined by the rules of chess (and the rectangular grid of a chessboard).
For example, the 0'th entries in both arrays mean "2 squares right and 1 square forward" - assuming x-coordinates increase left-to-right and y coordinates increase front-to-back.
You can determine the list for yourself by enumerating every possible combination of "two squares in one direction, and then one square at right-angles to it".
I am a beginner(first year uni student) programmer trying to solve this problem which i'm finding somewhat difficult. If you are to answer this question, don't provide me with a complex daunting algorithm that will leave me scratching my head. I'll really appreciate it if you explain it step my step (both logically/conceptually then through code)
The problem is as follows:image
I have tried to attempt it and my code only works for a certain case that i tested.
package com.company;
import java.lang.Math;
public class Main {
public static int[][] binary_partition(int array[], int k){
int x = (int) Math.pow(2,k);
int[][] partition = new int[((array.length/x)*2)][array.length/x];
int divisor = array.length/x;
if ((array.length % 2) != 0){
return partition;
}
if (divisor >= array.length-1){
return partition;
}
if (k==1){
return partition;
}
int p = 0;
for(int i=0;i<((array.length/x)*2);i++)
{
for (int j = 0; j<array.length/x;j++)
{
partition[i][j] = array[p];
p += 1;
}
}
return partition;
}
public static void main(String[] args){
int[] array = {3, 2, 4, 7, 8, 9, 2, 3};
int[][] result = binary_partition(array,2);
for (int[] x : result){
for (int y : x)
{
System.out.print(y + " ");
}
System.out.println();
}
}
}
Your question is unclear, but this solution creates a function that partitions an array with the right length into 2^k sets.
First, an interesting fact: using the bitshift operator << on an integer increases its value by a power of two. So to find out the size of your partition, you could write
int numPartitions = 1 << k; // Equivalent to getting the integer value of 2^k
With this fact, the function becomes
public static int[][] partition(int[] set, int k) {
if (set == null)
return null; // Don't try to partition a null reference
// If k = 0, the partition of the set is just the set
if (k == 0) {
int[][] partition = new int[1][set.length];
// Copy the original set into the partition
System.arraycopy(set, 0, partition[0], 0, set.length);
return partition;
}
int numPartitions = 1 << k; // The number of sets to partition the array into
int numElements = set.length / numPartitions; // The number of elements per partition
/* Check if the set has enough elements to create a partition and make sure
that the partitions are even */
if (numElements == 0 || set.length % numElements != 0)
return null; // Replace with an error/exception of your choice
int[][] partition = new int[numPartitions][numElements];
int index = 0;
for (int r = 0; r < numPartitions; r++) {
for (int c = 0; c < numElements; c++) {
partition[r][c] = set[index++]; // Assign an element to the partition
}
}
return partition;
}
There are a few lines of your code where the intention is not clear. For example, it is not clear why you are validating divisor >= array.length-1. Checking k==1 is also incorrect because k=1 is a valid input to the method. In fact, all your validation checks are not needed. All you need to validate is that array.length is divisible by x.
The main problem that you have seems to be that you mixed up the lengths of the resulting array.
The resulting array should have a length of array.length / x, and each of the subarrays should have a length of x, hence:
int[][] partition = new int[array.length/x][x];
If you also fix your bounds on the for loops, your code should work.
Your nested for loop can be rewritten as a single for loop:
for(int i = 0 ; i < array.length ; i++)
{
int index = i / x;
int subArrayIndex = i % x;
partition[index][subArrayIndex] = array[i];
}
You just need to figure out which indices a an element array[i] belongs by dividing and getting the remainder.
I'm trying to traverse through a maze recursively and im getting a stack overflow error, i understand the problem but am unable to fix it. Would i need to create a separate array to hold all the values that have been visited in the array or is there other ways that would be more efficient that use less lines of code?
Any suggestions would be greatly appreciated.
Here is the input;
5 6 // Row,Col
1 1 // Start Pos
3 4 // End Pos
1 1 1 1 1
1 0 0 0 1
1 0 1 0 1
1 0 1 0 1
1 0 1 0 1
1 1 1 1 1
Current code:
public class Solve {
private static int [][] MazeArray;
private static int Rows;
private static int Cols;
private static Point end = new Point();
private static Point start = new Point();
public static void ReadFileMakeMaze() {
Scanner in = new Scanner(System.in);
System.out.print("Select File: "); // Choose file
String fileName = in.nextLine();
fileName = fileName.trim();
String Buffer = "";
String[] Buffer2;
String[] MazeBuffer;
int Counter = 0;
try {
// Read input file
BufferedReader ReadFileContents = new BufferedReader(new FileReader(fileName+".txt"));
Buffer = ReadFileContents.readLine();
MazeBuffer = Buffer.split(" ");
// Creating MazeArray according to rows and columns from input file.
Rows = Integer.parseInt(MazeBuffer[0]);
Cols = Integer.parseInt(MazeBuffer[1]);
MazeArray = new int[Rows][Cols];
// Retrieving start locations and adding them to an X and Y coordinate.
String[] StartPoints = ReadFileContents.readLine().split(" ");
start.x = Integer.parseInt(StartPoints[0]);
start.y = Integer.parseInt(StartPoints[1]);
// Retrieving end locations and adding them to an X and Y coordinate.
String[] EndPoints = ReadFileContents.readLine().split(" ");
end.x = Integer.parseInt(EndPoints[0]);
end.y = Integer.parseInt(EndPoints[1]);
while(ReadFileContents.ready()) {
Buffer = ReadFileContents.readLine();
Buffer2 = Buffer.split(" ");
for(int i = 0; i < Buffer2.length; i++) {
MazeArray[Counter][i] = Integer.parseInt(Buffer2[i]); // Adding file Maze to MazeArray.
}
Counter ++;
}
}
catch(Exception e){
System.out.println(e); // No files found.
}
System.out.println(SolveMaze(start.x, start.y));
}
public static boolean SolveMaze(int x,int y) {
Print(); // Printing the maze
if(ReachedEnd(x,y)) {
MazeArray[x][y] = 5; // 5 represents the end
System.out.println(Arrays.deepToString(MazeArray));
return true;
}else if(MazeArray[x][y] == 1 || MazeArray[x][y] == 8){
return false;
}else {
MazeArray[x][y] = 8; // Marking the path with 8's
start.x = x;
start.y = y;
// Checking all directions
if(MazeArray[x][y - 1] == 0 ) {
System.out.println("Left");
SolveMaze(x, y - 1);
}else if(MazeArray[x + 1][y] == 0) {
System.out.println("Down");
SolveMaze(x + 1, y);
}else if(MazeArray[x - 1][y] == 0 ) {
System.out.println("Up");
SolveMaze(x - 1, y);
}else if(MazeArray[x][y + 1] == 0 ) {
System.out.println("Right");
SolveMaze(x, y + 1);
}else {
System.out.println("Debug");
MazeArray[x][y] = 0;
start.x = x;
start.y = y;
}
}
return false;
}
public static boolean DeadEnd(int x, int y) {
return true; // Solution needed
}
public static boolean ReachedEnd(int x, int y) {
if(x == end.x && y == end.y) { // Check if the end has been reached.
return true;
}else {
return false;
}
}
public static void Print() {
System.out.println(Arrays.deepToString(MazeArray));
}
public static void main(String[] args) {
ReadFileMakeMaze();
}
}
Firstly, like you mentioned in the question, creating a static Collection outside of SolveMaze which keeps a list of "visited" nodes would certainly help. If the node has being visited before then no need to check again.
Secondly, I believe there are a few mistakes within the above code. The table isn't generated correctly into the MazeArray[][], swap Rows and Cols around underneath "// Creating MazeArray according to rows and columns from input file."
The code also doesn't "find" a path, Arrays get defined as int[] array = new int[5] but to access it you have to use array[0] --> array[4] , what happens when I fix the maze is that you start on element 1,1 which is the '0' one row and column in from top left. Then you traverse down the list due to the ordering of the if else statements. After visiting each node you turn the nodes value to an 8. After 4 iterations the code is looking at the bottom 0 in the 2nd row, aka [4][1] above you is now and 8 and since 0's are the only elements you can move to, the node looks left, right and down and sees 1's, then turns and looks up and sees an 8. Thus finishing.
Thirdly, don't make checking up, down, left, right a set of "if else"'s, just a selection of "if's". This way the code will travel all paths. Then you can leave your 8's in and it will de facto not re-run the same node twice, rendering the 'visited' array unneeded. (Although as a general rule, mutating state when traversing through is unadvised)
Fourthly, I cannot get a stack overflow error from the above code so cannot answer the actual question.
On a side note - use tests and things like this become trivial, start small and build it up :) If unsure just checkout junit.
When I say efficient I mean code that isn't cpu intensive.
The Problem:
I have a field of blocks. Like in the following image:
Every single one of these blocks represents an instance of a self-made Block class. This block class has a List<Block> neighBours, where the neighbours of the block are stored. So every single block in the image knows which blocks are next to it.
What I want to do is to pick any block from this image, and compute how many "steps" away this block is. For example if I pick the block in the top left, I want to have a Map<Block, Integer> representing how many "steps" away each block is from the picked block. Like this:
Now before you say "Just store it's position X and Y in the block class and calculate the difference X + difference Y", that wouldn't work because the field can have gaps(represented by red color) between them like the following image:
And as you might notice, the block next to the gap that was first 4 steps away, is now 6 steps away. Thus the best way(I presume) to get how many steps away the other blocks are is by using a recursive algorith that makes use of the neighbour info. I couldn't make an efficient one myself and I was hoping someone might know something that works well.
Several problems I came across are the fact that because all blocks know their neighbours, the recursive algorithm would go indefinately back and forth between the first and second block. Or the fact that when using the algorithm on a 11x11 field, there were 3284 method calls, which seems waaay too high for an 11x11 field.
Question:
So the question I have is: What is an efficient way, using the knowledge of what neighbours each block has, to get how many steps away each block is.
Code:
This is the current code that I have incase anyone wants to see it.
public class Block
{
List<Block> neighBours;
public Block(List<Block> neighBours)
{
this.neighBours = neighBours;
}
public Map<Block, Integer> getStepsAway()
{
Map<Block, Integer> path = new HashMap<Block, Integer>();
getPaths(path, 0, 100);
return path;
}
public void getPaths(Map<Block, Integer> path, int pathNumber, int maxPathNumber)
{
if(pathNumber <= maxPathNumber)
{
for(Block block : neighBours)
{
Integer thePathNumber = path.get(block);
if(thePathNumber != null)
{
if(pathNumber < thePathNumber)
{
path.put(block, pathNumber);
block.getPaths(path, pathNumber + 1, maxPathNumber);
}
}
else
{
path.put(block, pathNumber);
block.getPaths(path, pathNumber + 1, maxPathNumber);
}
}
}
}
}
Recursive algorithms are doomed to fail on a large grid. Java is not designed for deep recursions and can only withstand a few thousands recursive calls before failing with a StackOverflowException. Only iterative solutions are a reasonible approach for large pathfinding problems in Java.
Of course you can always use a classic pathfinding algorithm such as A*, but you would have to apply it for each cell, which would be extremely expensive.
Indeed, your problem is a bit particular in the sense you want to calculate the minimum distance to all cells and not only just one. Therefore, you can do it in a more clever way.
One property of your problem is that given A and B, if the minimal path from A to B contains C then this path is also minimal from A to C and from C to B. That's what my intuition tells me, but it would need to be proven before implementing my suggestion.
The algorithm I propose is efficient, uses O(n) memory and has O(n^2) runtime complexity (cannot be faster since you need to set this many cells in the array):
start with your first point and set the distance of all its valid neighbours to 1. Doing so, you will record the border, which is all the cells at distance 1 from the first cell.
then, you iterate over the border and take all their neighbours which have not already been assigned a distance and assign them distance 2. All cells of distance 2 become your new border.
iterate until the border is empty
Below is a full working solution. The code may be improved in various ways using more convenience methods for initializing and printing matrices of objects and primitive integers, but you get the idea:
public class Solution {
public enum Cell { FREE, BLOCKED }
// assuming cells is a rectangular array with non-empty columns
public static int[][] distances(Cell[][] cells, ArrayCoordinate startingPoint) {
int[][] distances = new int[cells.length][cells[0].length];
// -1 will mean that the cell is unreachable from the startingPoint
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[0].length; j++) {
distances[i][j] = -1;
}
}
distances[startingPoint.i][startingPoint.j] = 0;
Set<ArrayCoordinate> border = startingPoint.validNeighbours(cells);
for (int currentDistance = 1; !border.isEmpty(); currentDistance++) {
Set<ArrayCoordinate> newBorder = new HashSet<>();
for (ArrayCoordinate coord : border) {
distances[coord.i][coord.j] = currentDistance;
for (ArrayCoordinate neighbour : coord.validNeighbours(cells)) {
if (distances[neighbour.i][neighbour.j] < 0) {
newBorder.add(neighbour);
}
}
}
border = newBorder;
}
return distances;
}
private static class ArrayCoordinate {
public ArrayCoordinate(int i, int j) {
if (i < 0 || j < 0) throw new IllegalArgumentException("Array coordinates must be positive");
this.i = i;
this.j = j;
}
public final int i, j;
public Set<ArrayCoordinate> validNeighbours(Cell[][] cells) {
Set<ArrayCoordinate> neighbours = new HashSet<>();
// inlining for not doing extra work in a loop iterating over (-1, 1) x (-1, 1). If diagonals are allowed
// then switch for using a loop
addIfValid(cells, neighbours, 1, 0);
addIfValid(cells, neighbours, -1, 0);
addIfValid(cells, neighbours, 0, 1);
addIfValid(cells, neighbours, 0, -1);
return neighbours;
}
private void addIfValid(Cell[][] cells, Set<ArrayCoordinate> neighbours, int dx, int dy) {
int x = i + dx, y = j + dy;
if (0 <= x && 0 <= y && x < cells.length && y < cells[0].length && cells[x][y] == Cell.FREE) {
neighbours.add(new ArrayCoordinate(i + dx, j + dy));
}
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArrayCoordinate point = (ArrayCoordinate) o;
if (i != point.i) return false;
if (j != point.j) return false;
return true;
}
#Override
public int hashCode() {
int result = i;
result = 31 * result + j;
return result;
}
}
public static void main(String[] args) {
int n = 11, m = 5;
Cell[][] cells = new Cell[n][m];
cells[1][1] = Cell.BLOCKED;
cells[1][2] = Cell.BLOCKED;
cells[2][1] = Cell.BLOCKED;
ArrayCoordinate startingPoint = new ArrayCoordinate(5, 2);
System.out.println("Initial matrix:");
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[0].length; j++) {
if (cells[i][j] == null) {
cells[i][j] = Cell.FREE;
}
if (startingPoint.i == i && startingPoint.j == j) {
System.out.print("S ");
} else {
System.out.print(cells[i][j] == Cell.FREE ? ". " : "X ");
}
}
System.out.println();
}
int[][] distances = distances(cells, startingPoint);
System.out.println("\nDistances from starting point:");
for (int i = 0; i < distances.length; i++) {
for (int j = 0; j < distances[0].length; j++) {
System.out.print((distances[i][j] < 0 ? "X" : distances[i][j]) + " ");
}
System.out.println();
}
}
}
Output:
Initial matrix:
. . . . .
. X X . .
. X . . .
. . . . .
. . . . .
. . S . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Distances from starting point:
7 8 7 6 7
6 X X 5 6
5 X 3 4 5
4 3 2 3 4
3 2 1 2 3
2 1 0 1 2
3 2 1 2 3
4 3 2 3 4
5 4 3 4 5
6 5 4 5 6
7 6 5 6 7
Bonus
I almost cried when I saw all this boilerplate in my Java solution, so I wrote a shorter (perhaps slightly less efficient) version in Scala:
object ScalaSolution {
sealed abstract class Cell
object Free extends Cell
object Blocked extends Cell
// assuming cells is a rectangular array with non-empty columns
def distances(cells: Array[Array[Cell]], startingPoint: (Int, Int)) = {
// -1 will mean that the cell is unreachable from the startingPoint
val distances = Array.fill[Int](cells.length, cells(0).length)(-1)
distances(startingPoint._1)(startingPoint._2) = 0
var (currentDistance, border) = (1, validNeighbours(cells, startingPoint))
while (border.nonEmpty) {
border.foreach { case (i, j) => distances(i)(j) = currentDistance }
border = border.flatMap(validNeighbours(cells, _)).filter { case (i, j) => distances(i)(j) < 0 }
currentDistance += 1
}
distances
}
private def validNeighbours(cells: Array[Array[Cell]], startingPoint: (Int, Int)) = {
// inlining for not doing extra work in a for yield iterating over (-1, 1) x (-1, 1). If diagonals are allowed
// then switch for using a for yield
Set(neighbourIfValid(cells, startingPoint, ( 1, 0)),
neighbourIfValid(cells, startingPoint, (-1, 0)),
neighbourIfValid(cells, startingPoint, ( 0, 1)),
neighbourIfValid(cells, startingPoint, ( 0, -1)))
.flatten
}
private def neighbourIfValid(cells: Array[Array[Cell]], origin: (Int, Int), delta: (Int, Int)) = {
val (x, y) = (origin._1 + delta._1, origin._2 + delta._2)
if (0 <= x && 0 <= y && x < cells.length && y < cells(0).length && cells(x)(y) == Free) {
Some(x, y)
} else None
}
def main (args: Array[String]): Unit = {
val (n, m) = (11, 5)
val cells: Array[Array[Cell]] = Array.fill(n, m)(Free)
cells(1)(1) = Blocked
cells(1)(2) = Blocked
cells(2)(1) = Blocked
val startingPoint = (5, 2)
println("Initial matrix:")
printMatrix(cells)((i, j, value) => if ((i, j) == startingPoint) "S" else if (value == Free) "." else "X")
val distancesMatrix = distances(cells, startingPoint)
println("\nDistances from starting point:")
printMatrix(distancesMatrix)((i, j, value) => if (value < 0) "X" else value.toString)
}
private def printMatrix[T](matrix: Array[Array[T]])(formatter: (Int, Int, T) => String) = {
for (i <- 0 until matrix.length) {
for (j <- 0 until matrix(0).length) {
print(formatter(i, j, matrix(i)(j)) + " ")
}
println()
}
}
}
I believe there is a DP (dynamic programming) solution to this problem, looking at this, code below. I realize this is for finding all possible paths to a cell but it can give insight on your condition about 'blanks' or 'walls'
#include <iostream>
using namespace std;
// Returns count of possible paths to reach cell at row number m and column
// number n from the topmost leftmost cell (cell at 1, 1)
int numberOfPaths(int m, int n)
{
// Create a 2D table to store results of subproblems
int count[m][n];
// Count of paths to reach any cell in first column is 1
for (int i = 0; i < m; i++)
count[i][0] = 1;
// Count of paths to reach any cell in first column is 1
for (int j = 0; j < n; j++)
count[0][j] = 1;
// Calculate count of paths for other cells in bottom-up manner using
// the recursive solution
for (int i = 1; i < m; i++)
{
for (int j = 1; j < n; j++)
// By uncommenting the last part the code calculatest he total
// possible paths if the diagonal Movements are allowed
count[i][j] = count[i-1][j] + count[i][j-1]; //+ count[i-1][j-1];
}
return count[m-1][n-1];
}
Its an assignment task,I have spend 2 days to come up with a solution but still having lots of confusion,however here I need to make few points clear. Following is the problem:
Yuckdonald’s is considering opening a series of restaurant along QVH. n possible locations are along a straight line and the distances of these locations from the start of QVH are in miles and in increasing order m1, m2, ...., mn. The constraints are as follows:
1. At each location, Yuckdonald may open one restaurant and expected profit from opening a restaurant at location i is given as pi
2. Any two restaurants should be at least k miles apart, where k is a positive integer
My solution:
public class RestaurantProblem {
int[] Profit;
int[] P;
int[] L;
int k;
public RestaurantProblem(int[] L , int[] P, int k) {
this.L = L;
this.P = P;
this.k = k;
Profit = new int[L.length];
}
public int compute(int i){
if(i==0)
return 0;
Profit[i]= P[i]+(L[i]-L[i-1]< k ? 0:compute(i-1));//if condition satisfies then adding previous otherwise zero
if (Profit[i]<compute(i-1)){
Profit[i] = compute(i-1);
}
return Profit[i];
}
public static void main(String args[]){
int[] m = {0,5,10,15,19,25,28,29};
int[] p = {0,10,4,61,21,13,19,15};
int k = 5;
RestaurantProblem rp = new RestaurantProblem(m, p ,k);
rp.compute(m.length-1);
for(int n : rp.Profit)
System.out.println(n);
}
}
This solution giving me 88 however if I exclude (Restaurant at 25 with Profit 13) and include (Restaurant 28 with profit 19) I can have 94 max...
point me if I am wrong or how can I achieve this if its true.
I was able to identify 2 mistakes:
You are not actually using dynamic programming
, you are just storing the results in a data structure, which wouldn't be that bad for performance if the program worked the way you have written it and if you did only 1 recursive call.
However you do at least 2 recursive calls. Therefore the program runs in Ω(2^n) instead of O(n).
Dynamic programming usually works like this (pseudocode):
calculate(input) {
if (value already calculated for input)
return previously calculated value
else
calculate and store value for input and return result
}
You could do this by initializing the array elements to -1 (or 0 if all profits are positive):
Profit = new int[L.length];
Arrays.fill(Profit, -1); // no need to do this, if you are using 0
public int compute(int i) {
if (Profit[i] >= 0) { // modify the check, if you're using 0 for non-calculated values
// reuse already calculated value
return Profit[i];
}
...
You assume the previous restaurant can only be build at the previous position
Profit[i] = P[i] + (L[i]-L[i-1]< k ? 0 : compute(i-1));
^
Just ignores all positions before i-1
Instead you should use the profit for the last position that is at least k miles away.
Example
k = 3
L 1 2 3 ... 100
P 5 5 5 ... 5
here L[i] - L[i-1] < k is true for all i and therefore the result will just be P[99] = 5 but it should be 34 * 5 = 170.
int[] lastPos;
public RestaurantProblem(int[] L, int[] P, int k) {
this.L = L;
this.P = P;
this.k = k;
Profit = new int[L.length];
lastPos = new int[L.length];
Arrays.fill(lastPos, -2);
Arrays.fill(Profit, -1);
}
public int computeLastPos(int i) {
if (i < 0) {
return -1;
}
if (lastPos[i] >= -1) {
return lastPos[i];
}
int max = L[i] - k;
int lastLastPos = computeLastPos(i - 1), temp;
while ((temp = lastLastPos + 1) < i && L[temp] <= max) {
lastLastPos++;
}
return lastPos[i] = lastLastPos;
}
public int compute(int i) {
if (i < 0) {
// no restaurants can be build before pos 0
return 0;
}
if (Profit[i] >= 0) { // modify the check, if you're using 0 for non-calculated values
// reuse already calculated value
return Profit[i];
}
int profitNoRestaurant = compute(i - 1);
if (P[i] <= 0) {
// no profit can be gained by building this restaurant
return Profit[i] = profitNoRestaurant;
}
return Profit[i] = Math.max(profitNoRestaurant, P[i] + compute(computeLastPos(i)));
}
To my understanding, the prolem can be modelled with a two-dimensional state space, which I don't find in the presented implementation. For each (i,j) in{0,...,n-1}times{0,...,n-1}` let
profit(i,j) := the maximum profit attainable for selecting locations
from {0,...,i} where the farthest location selected is
no further than at position j
(or minus infinity if no such solution exist)
and note that the recurrence relation
profit(i,j) = min{ p[i] + profit(i-1,lastpos(i)),
profit(i-1,j)
}
where lastpos(i) is the location which is farthest from the start, but no closer than k to position i; the first case above corresponds to selection location i into the solution while the second case corresponds to omitting location j in the solution. The overall solution can be obtained by evaluating profit(n-1,n-1); the evaluation can be done either recursively or by filling a two-dimensional array in a bottom-up manner and returning its contents at (n-1,n-1).