An efficient way to get and store the shortest paths - java

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

Related

Problem with a Java program that counts number of non self-intersecting paths between upper left to bottom right of a square array

It is well known that when one is allowed only to move right and down, the number of paths between the upper left cell to the bottom right cell of a rectanglular grid with side lengths n,m is the binomial coefficient n+m on n. I tried to think, at first in a mathematical manner, about the number of such paths when one is also allowed to move left and up; obviously the only way to give meaningful answer to such a question is to count non self-intersecting paths that do not go outside the rectangle (without those restrictions, the number of paths is infinite)
Since I had no idea how to count the number of such paths combinatorially, I wrote a java program that counts such paths and prints the paths, which I restricted to square arrays. However, already in an array of size 3x3, the program prints only 9 paths, while checking the number of such paths manually gave 12 paths. Here is the program:
public class pathCalculator {
public static int pathsCalculator(boolean[][] arr) {
return pathsCalculator(arr, 0, 0, "");
}
public static int pathsCalculator(boolean[][] arr, int i, int j, String s) {
if (i < 0 || i > arr.length - 1 || j < 0 || j > arr[0].length - 1) {
return 0;
} else if (arr[i][j] == false) {
return 0;
}
if (i == arr.length - 1 && j == arr[0].length - 1) {
s = s + "[" + (arr.length - 1) + "," + (arr.length - 1) + "]";
System.out.println(s);
return 1;
} else {
arr[i][j] = false;
s = s + "[" + i + "," + j + "]";
boolean[][] arr1 = new boolean[arr.length][arr.length];
for (int n = 0; n <= arr.length - 1; n++) {
for (int m = 0; m <= arr.length - 1; m++) {
arr1[n][m] = arr[n][m];
}
}
return pathsCalculator(arr1, i + 1, j, s) + pathsCalculator(arr1, i - 1, j, s) + pathsCalculator(arr1, i, j + 1, s) + pathsCalculator(arr1, i, j - 1, s);
}
}
}
The boolean array that is checked is initialized in the main program to be a square of "true"'s.
The main ideas of the program are therefore:
Recursion - each time the method calls to four variations of itself, which correspond to the four possibilies of: moving down,up,right and left.
Flagging forbidden cells - each time the path approaches a given cell, the program changes the cell's boolean value from true to false. The second if condition causes the program to return 0 in case we arrived at a forbidden cell (this indicates the path is self-intersecting).
Creating copies of the original boolean array - to prevent the different paths from interacting with each other on the same board, in each recursive step the previous boolean array values are copied into a new array.
So what is the problem with what I wrote? why it counts only a part of the total number of paths?
A minor change in the program, but of critical importance, enables the program to return the correct number of non self-intersecting paths bewteen the upper left cell to bottom right cell. In the coping part of the code, just before the recursive call, one should initialize 4 arrays instead of one, each of which is an identical copy of the previous array, and then let each of the four calls of pathscalculator method continue with a different copy of the array.
Here is the corrected version of the program:
public class pathCalculator{
public static int pathsCalculator(boolean[][] arr)
{
return pathsCalculator(arr,0,0,"");
}
public static int pathsCalculator(boolean [][] arr, int i, int j,String s)
{
if(i<0||i>arr.length-1||j<0||j>arr[0].length-1)
{
return 0;
}
else if(arr[i][j]==false)
{
return 0;
}
if(i==arr.length-1&&j==arr[0].length-1)
{
s = s+"["+(arr.length-1)+","+(arr.length-1)+"]";
System.out.println(s);
return 1;
}
else
{
arr[i][j]=false;
s = s+"["+i+","+j+"]";
boolean[][] arr1 = new boolean[arr.length][arr.length];
boolean[][] arr2 = new boolean[arr.length][arr.length];
boolean[][] arr3 = new boolean[arr.length][arr.length];
boolean[][] arr4 = new boolean[arr.length][arr.length];
for(int n=0;n<=arr.length-1;n++){
for(int m=0;m<=arr.length-1;m++){
arr1[n][m]=arr[n][m];
arr2[n][m]=arr[n][m];
arr3[n][m]=arr[n][m];
arr4[n][m]=arr[n][m];
}
}
return pathsCalculator(arr1,i+1,j,s)+pathsCalculator(arr2,i-1,j,s)+pathsCalculator(arr3,i,j+1,s)+pathsCalculator(arr4,i,j-1,s);
}
}
}
Here is the main function:
public class pathCalculatorTester
{
public static void main(String[] args)
{
boolean[][] arr ={{true,true,true},{true,true,true}
,{true,true,true}};
System.out.println(pathCalculator.pathsCalculator(arr));
}
}
And this is the output:
[0,0][1,0][2,0][2,1][1,1][0,1][0,2][1,2][2,2]
[0,0][1,0][2,0][2,1][1,1][1,2][2,2]
[0,0][1,0][2,0][2,1][2,2]
[0,0][1,0][1,1][2,1][2,2]
[0,0][1,0][1,1][0,1][0,2][1,2][2,2]
[0,0][1,0][1,1][1,2][2,2]
[0,0][0,1][1,1][2,1][2,2]
[0,0][0,1][1,1][1,2][2,2]
[0,0][0,1][1,1][1,0][2,0][2,1][2,2]
[0,0][0,1][0,2][1,2][2,2]
[0,0][0,1][0,2][1,2][1,1][2,1][2,2]
[0,0][0,1][0,2][1,2][1,1][1,0][2,0][2,1][2,2]
12
It returns the correct number of paths for 3x3 square, but since I don't have full understanding why it was nessecary to initialize 4 arrays insted of one, I'm not sure it works well for larger arrays. By the way, the function f(n) where n is the length size of the square and f is the number of paths, appears to grow amazingly fast - for 4x4 squares the number of paths that the program returned is 184, and for 5x5 squares the number is 8512.

Java maze inside of walls and get all possible paths

I know that there's a lot of other maze solver here. Though I would like to have my own approach and I think my problem is a bit different from the others.
As of now, here's what I've started and hopefully I can achieve what I have in mind at the moment.
private static int getPossiblePaths(File f) throws IOException {
int counts = 0; // hope to return all possible paths
// read input file then put it on list string
List<String> lines = Files.lines(f.toPath()).collect(Collectors.toList());
// get the row and column (dimensions)
String[] dimensions = lines.get(0).split(",");
//initalize sub matrix of the maze dimensions and ignoring the top and bottom walls
int[][] mat = new int[Integer.valueOf(dimensions[0]) - 2 ][Integer.valueOf(dimensions[1]) - 2];
//for each line in the maze excluding the boundaries (top and bottom)
for( int i = 2 ; i < lines.size() - 1 ; i++) {
String currLine = lines.get(i);
int j = 0;
for(char c : currLine.toCharArray()) {
mat[i-2][j] = (c=='*' ? 'w' : c=='A' ? 'a' : c=='B' ? 'b' : 's');
// some conditional statements here
}
}
// or maybe some conditional statements here outside of the loop
return counts;
}
And the maze from a text file is look like this. Please note that the A could be anywhere and same as B. The only movements allowed is to right and down.
5,5
*****
*A *
* *
* B*
*****
Expected output for the maze above is 6 (possible paths from A to B).
EDIT: Also the maze from the text file could be like this:
8,5
********
* A *
* B*
* *
********
So with my current code, it is getting the dimensions (first line) and removing the top and bottom part of the maze (boundaries). So there's only 3 lines of characters currently stored in the mat array. And some encoding of each characters of the text file (#=w(wall), A=a(start), B=b(end), else s(space))
I would like to have some conditional statements inside of the foreach to probably store the each of characters inside of an ArrayList. Though I'm not sure if this approach will just make my life harder.
Any suggestions, tips, advice or other easier approach from you guys will greatly appreciated! Thank you
The idea to create mat is fine. I would not bother to strip off the first and last line, as in fact it will be easier to work with when you keep them. That way a row reference like i-1 will not go out of range when you are at a non-wall location.
I would also not store characters like w in there, but specific numbers, like -1 for wall, 0 for free. Also store 0 for "A" and "B". When encountering those two letters, you could store their coordinates in specific variables (e.g. rowA, colA, rowB, colB). You may need to check whether B is down-right from A, as otherwise B is certainly not reachable from A.
So I would define mat as follows (note that I reversed the dimensions, because your second example demonstrates that the first line of the input has them in that order):
int[][] mat = new int[Integer.valueOf(dimensions[1])]
[Integer.valueOf(dimensions[0])];
int colA = mat[0].length;
int rowA = 0;
int colB = colA;
int rowB = 0;
for (int i = 0; i < mat.length; i++) {
String currLine = lines.get(i+1);
int j = 0;
for (char c : currLine.toCharArray()) {
mat[i][j] = c == '*' ? -1 : 0;
if (c == 'B') {
if (colA > j) return 0; // B unreachable from A
rowB = i;
colB = j;
} else if (c == 'A') {
if (colB < j) return 0; // B unreachable from A
rowA = i;
colA = j;
}
j++;
}
}
With this setup you can reuse mat to store the number of paths from A to the current position. The value 0 at A should be set to 1 (there is one path from A to A), and then it is a matter of adding up the value from the cell above and left, making sure that -1 is treated as a 0.
mat[rowA][colA] = 1;
for (int i = rowA; i <= rowB; i++) {
for (int j = colA; j <= colB; j++) {
if (mat[i][j] == 0) { // not a wall?
// count the number of paths that come from above,
// plus the number of paths that come from the left
mat[i][j] = Math.max(0, mat[i-1][j]) + Math.max(0, mat[i][j-1]);
}
}
}
return mat[rowB][colB]; // now this has the number of paths we are looking for
Although a recursive method will also work, I would suggest the above dynamic programming approach, since that way you avoid to recalculate counts for a certain cell several times (when coming there via different DFS paths). This solution has a linear time complexity.
I propose a simple recursion with 2 calls: down and right.
This is the code:
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
public class JavaMazeInsideOfWallsAndGetAllPossiblePaths {
public static void main(String[] args) throws IOException, URISyntaxException {
Path mazePath = Paths.get( MethodHandles.lookup().lookupClass().getClassLoader()
.getResource("maze.txt").toURI());
File mazeFile = mazePath.toFile();
System.out.println(getPossiblePaths(mazeFile));
}
private static int getPossiblePaths(File f) throws IOException {
// read input file then put it on list string
List<String> lines = Files.lines(f.toPath()).collect(Collectors.toList());
// get the row and column (dimensions)
String[] dimensions = lines.get(0).split(",");
//initalize sub matrix of the maze dimensions and ignoring the top and bottom walls
int[][] mat = new int[Integer.valueOf(dimensions[0]) - 2 ][Integer.valueOf(dimensions[1]) - 2];
int fromRow = -1, fromCol = -1, toRow = -1, toCol = -1;
for( int i = 2 ; i < lines.size() - 1 ; i++) {
String currLine = lines.get(i);
int j = 0;
for(char c : currLine.toCharArray()) {
switch(c) {
case '*':
continue; // for loop
case 'A':
mat[i-2][j] = 0;
fromRow = i-2;
fromCol = j;
break;
case 'B':
mat[i-2][j] = 2;
toRow = i-2;
toCol = j;
break;
default:
mat[i-2][j] = 1;
}
j++;
}
}
return getPossiblePathsRecursive(mat, fromRow, fromCol, toRow, toCol);
}
private static int getPossiblePathsRecursive(int[][] mat, int i, int j, int rows, int columns) throws IOException {
if(i > rows || j > columns) {
return 0;
}
if(mat[i][j] == 2) {
return 1;
}
return getPossiblePathsRecursive(mat, i+1, j, rows, columns) +
getPossiblePathsRecursive(mat, i, j + 1, rows, columns);
}
}
Notes:
1. The validation step is skipped (assuming that the input data is in a valid format)
2. The walls are ignored (assuming that there are always 4 walls - first row, last row, first column, last column. These walls are assumed to be represented as '*')

My merge sort code is completely correct, yet no sorting is taking place

I have a public static int Dlist[ ][ ] declared in the class and the below mentioned functions are written.
I saw a similar code (only the basic mergesort code on GeeksforGeeks) where they take k = 1 and their code works completely welll. where as, my does something but the result is not what is expected. i am not able to understand why k=1 working ?
I'd like to know two things.
1) why k = 1 works (https://www.geeksforgeeks.org/java-program-for-merge-sort/)
Shouldn't it be k = 0 and instead of arr[k] it should have been arr[l+k]
2) What is the problem in my code? Why is it not doing anything?
*Also LI is left indes, RI is right index, MI is middle index, ii is for Dlist[ ][ii]
public static void mergeSort(int Dlist[][], int ii, int li, int ri)
{
if(ri > li)
{
int m = (li+ri)/2;
mergeSort(Dlist, ii, li, m);
mergeSort(Dlist, ii, m + 1, ri);
Merge(Dlist, ii, li, m, ri);
}
}
public static void Merge(int Dlist[][], int ii, int li, int m, int ri)
{
int la[][] = new int[m-li+1][2];
int ra[][] = new int[ri-m][2];
int i,j,k;
for(i = 0; i < m-li+1; i++)
{
la[i][0] = Dlist[li+i][0];
la[i][1] = Dlist[li+i][1];
}
for(i = 0; i < ri-m; i++)
{
ra[i][0] = Dlist[m+i+1][0];
ra[i][1] = Dlist[m+i+1][1];
}
i = 0; j = 0; k = 0;
while ((i < m-li+1) && (j < m-ri))
{
if(la[i][ii] < ra[j][ii])
{
Dlist[(li+k)][ii] = la[i][ii];
if(ii == 1)
{
Dlist[(li+k)][0] = la[i][0];
}
i++;
k++;
}
else
{
Dlist[(li+k)][ii] = ra[j][ii];
if(ii == 1)
{
Dlist[(li+k)][0] = ra[j][0];
}
j++;
k++;
}
}
while (i < m-li+1)
{
Dlist[li+k][ii] = la[i][ii];
if(ii == 1)
{
Dlist[li+k][0] = la[i][0];
}
i++;
k++;
}
while (j < m-ri)
{
Dlist[li+k][ii] = ra[j][ii];
if(ii == 1)
{
Dlist[li+k][0] = ra[j][0];
}
j++;
k++;
}
}
The aim of the code is to convert this :-
*The sorting is done with respect to Dlist[ ][1] in descending order.
2 4 5 7 8
4 2 7 9 1
into this :-
7 5 2 4 8
9 7 4 2 1
But the functions don't do anything.
Final Update :-
I was able to make the same code work by copying Dlist[][1] to another array. Then applying those functions on this new copied array and in merge function, while modifying copied array, i made same modifications in Dlist. Don't know why it worked that way. But that worked for me.
It's not k = 1, it's k = l (in upper case K = L).
mergeSort(Dlist, ii, m + 1, mi); should be mergeSort(Dlist, ii, m + 1, ri);
Regardless if ii == 0 or ii == 1, merge should always copy DList[..][0] and DList[..][1].
The code would be simpler if ri was the ending index (last index + 1), eliminating all the +1 in the code. You could change the index names to bgn or bi (instead of li) and end or ei (instead of ri).
Take a look at the wiki example for top down merge sort. It does a one time copy of the original array, into a one time allocated working array, then swaps the array names in the recursive calls so that the direction of merge corresponds to the level of recursion, eliminating the need to create sub-arrays or copy back. It also passes the beginning and ending indexes (as opposed to beginning and last index), and in the initial call beginning index = 0 and ending index = size of array (n).
https://en.wikipedia.org/wiki/Merge_sort#Top-down_implementation

Restaurant Maximum Profit using Dynamic Programming

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).

Recursive brute force maze solver Java

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.

Categories

Resources