need dynamic programming solution - java

The problem is the following:
Given a matrix of characters. In the very beginning of the game I am at position (0, 0) in the matrix. Depending on the character in the current position (i, j) I can move Up (if the current character is 'U'), Down if the current character is 'D', Right if the current character is 'R' and Left if the current character is 'L'. Once I reach position with character '*' I cannot move any more (there is exactly one such position). I have some time K in which I have to reach the character. I also have right to change characters, s.t. I can reach character ' * ' faster, but for each changing I pay cost of 1. In the end I have to return the min number of changes I have performed s.t. I have to reach character ' * ' in time k. If it is not possible I have to return -1.
My idea is as follows:
traverse the whole matrix, to find the position of character ' * '.
create boolean method isReachable(x, y, k), which tells me if character at position (x, y) is reachable from position (0, 0) for time k. Here is the method:
public static boolean isReachable(int x, int y, int time){
if(time < 0){
return false;
}
if(x == 0 && y == 0){
return true;
}
if(isInBounds(x-1, y)){
if(maze[x-1][y] == 'D'){
return isReachable(x-1, y, time-1);
}
}
if(isInBounds(x, y-1)){
if(maze[x][y-1] == 'R'){
return isReachable(x, y-1, time-1);
}
}
if(isInBounds(x+1, y)){
if(maze[x+1][y] == 'U'){
return isReachable(x+1, y, time-1);
}
}
if(isInBounds(x, y+1)){
if(maze[x][y+1] == 'L'){
return isReachable(x, y+1, time-1);
}
}
return false;
}
private static boolean isInBounds(int x, int y) {
if(x >= 0 && x <= N-1 && y >= 0 && y <= M-1){
return true;
}
return false;
}
If the method return true - I output 0 (i.e. there is no need to change any square in the matrix).
If the method return false - I want to perform another method which will tell me the min number of changes. However I dont know how to write it. This is my draft that obiously doesnt work:
private static int find(int x, int y, int k) {
int res = 0;
if(k < 0){ //my idea is that if the time become < 0 it means that the point is unreachable, i.e. I have to output 0; Howevr this doesnt output 0, just gives 0 to the upper levels of a recursion tree;
return -1;
}
if(x == 0 && y == 0){
res = 0;
}
else{
int down;
if(isInBounds(x-1, y) ){
if(maze[x-1][y] == 'D'){
down = find(x-1, y, k-1);
}
else{
down = 1 + find(x-1, y, k-1);
}
}
else{
down = Integer.MAX_VALUE;
}
int left;
if(isInBounds(x, y+1) ){
if(maze[x][y+1] == 'L'){
left = find(x, y+1, k-1);
}
else{
left = 1 + find(x, y+1, k-1);
}
}
else{
left = Integer.MAX_VALUE;
}
int right;
if(isInBounds(x, y-1) ){
if(maze[x][y-1] == 'R'){
right = find(x, y-1, k-1);
}
else{
right = 1 + find(x, y-1, k-1);
}
}
else{
right = Integer.MAX_VALUE;
}
int up;
if(isInBounds(x+1, y) ){
if(maze[x+1][y] == 'U'){
up = find(x+1, y, k-1);
}
else{
up = 1 + find(x+1, y, k-1);
}
}
else{
up = Integer.MAX_VALUE;
}
res = min(left, right, up, down);
}
return res;
}
As I wrote in the comments I have two very basic cases which I dont know how to perform:
when the time < 0 -> it means that the point is unreachable, i.e. I have to output -1 (but I dont know how to do it)
if I am at point (0, 0) I dont have to do any changes - return 0
else I check the neighbouring squares for their letters and return what I have from them.
Can someone help me with general idea, because I think mine is wrong. I the problem description it was said that we have to use dynamic programming and recursion

I haven't solve the problem, but I think my solution is right.
create dp[i][j][dir][step], means the cost in pos(i,j), the direction is dir and need 'step' steps to the position '*'.
assume '*' in I,J, so we need to calculate dp[I][J][0|1|2|3][0].
tot time is states*move, which is (50*50*4*1000)*(4*4). It is enough to solve the problem.

Related

Binary Search 2D array - Java

I am stuck on the following question:
Given a int two-dimensional matrix mat of size n2 where n = 2k, search for an integer k.
The matrix's rows and columns are sorted.
If we split the matrix in quarters, each quarter is also sorted. For example, given this matrix:
-4 -2 5 9
2 5 12 13
13 20 25 25
22 24 49 57
If we split it into quarters, we can see that all of the numbers in the first quarter are equal or less than numbers in the second quarter.
In order to obtain an efficient algorithm, I thought of making a recursive binary search in on the two dimensions but it fails to search for 2 on the previous matrix.
Here's the code:
public static boolean find(int[][] mat, int x){
return find2(mat, x, 0, mat.length-1,0, mat.length-1);
}
private static boolean find2(int[][] mat, int x, int lorow, int hirow,int locol,int hicol){
if(mat.length==0) return false;
if(lorow>hirow || locol>hicol) return false;
int midrow=(lorow+hirow)/2;
int midcol=(locol+hicol)/2;
if(mat[midrow][midcol] == x ) return true;
else if(mat[midrow][midcol] < x)
return find2(mat,x,lorow,midrow,midcol+1,hicol) || find2(mat,x,midrow+1,hirow,locol,midcol) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
else
return find2(mat,x,lorow,midrow,locol,midcol-1) || find2(mat,x,midrow,hirow,locol,midcol-1) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
}
Please advise.
Your mistake is at here in your code.
else
return find2(mat,x,lorow,midrow,locol,midcol-1) || find2(mat,x,midrow,hirow,locol,midcol-1) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
Here in first two functions, You are removing middle column from your search space. You need to include it as element can be present at the middle column. Another mistake is in the last call find2(mat,x,midrow+1,hirow,midcol+1,hicol).
If your search element is smaller than the middle element, You should choose top-left quadrant of the middle element and ignore the bottom-right quadrant. You have mistakenly considered here bottom-right quadrant over top-left quadrant.
After making changes accordingly the return function in else looks like:
return find2(mat,x,lorow,midrow,locol,midcol) || find2(mat,x,lorow,midrow,midcol+1,hicol) ||find2(mat,x,midrow+1,hirow,locol,midcol);
This solved the problem and it returns true for -2.
Updated Code:
private static boolean find2(int[][] mat, int x, int lorow, int hirow,int locol,int hicol){
if(mat.length==0) return false;
if(lorow>hirow || locol>hicol) return false;
if(lorow==hirow && locol==hicol && mat[lorow][locol]!=x)
return false;
int midrow=(lorow+hirow)/2;
int midcol=(locol+hicol)/2;
if(mat[midrow][midcol] == x ) return true;
else if(mat[midrow][midcol] < x)
return find2(mat,x,lorow,midrow,midcol+1,hicol) || find2(mat,x,midrow+1,hirow,locol,midcol) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
else
return find2(mat,x,lorow,midrow,locol,midcol) || find2(mat,x,lorow,midrow,midcol+1,hicol) ||find2(mat,x,midrow+1,hirow,locol,midcol);
}
If your matrix row and column are sorted you can use below code.
public int search(int mat[][], int n, int x) {
int i = 0, j = n - 1;
while (i < n && j >= 0) {
if (mat[i][j] == x) {
System.out.println("Found at" + i + j);
return 1;
}
if (mat[i][j] > x)
j--;
else // if mat[i][j] < x
i++;
}
System.out.println("not Found at");
return 0;
}

What is wrong with my Java recursive function?

I'm trying to write a relatively straightforward recursive program in Java to compute all the possible ways to traverse a 4x4 matrix (not necessarily traveling through every spot), starting at the top left and ending in the bottom right spaces. I use a 2-D array to do this, marking off visited spaces with "1"s as I go.
It's been a while since I've worked recursively and I can't seem to get the output I expect. The output from the code below is "2" - obviously, the result should be much higher. I know there's something tiny I'm overlooking. Can someone tell me what it is?
public static void main(String[] args) {
int[][] matrix = new int[4][4];
int result = moveRobot(matrix, 0, 0);
System.out.print(result + "");
}
public static int moveRobot(int[][] matrix, int x, int y) {
if (x == 3 && y == 3) {
return 1;
} else if (x < 0 || y < 0 || x > 3 || y > 3) {
return 0;
} else if (matrix[x][y] == 1) {
return 0;
} else {
matrix[x][y] = 1;
return moveRobot(matrix, x, y+1) + moveRobot(matrix, x+1, y) + moveRobot(matrix, x, y-1) +
moveRobot(matrix, x-1, y);
}
}
The problem is that the matrix is not copied but passed by value of the reference to it. Every time you modify it such in matrix[x][y] = 1 other successive code paths will see the modification instead that working on an unmodified state.
For example here:
moveRobot(matrix, x, y+1) + moveRobot(matrix, x+1, y)
Entering the first call will modify matrix, so in second moveRobot call you'd end up with 1 in matrix[x][y+1] while that's not what you want.

Avoid out of bounds exception in 2D array

I'm trying to solve a problem which uses a 2D array, the problem of a rat in a maze.
While checking the conditions trying to compile, it finds an Array index out of bounds exception... how can I check the values so it doesn't go out of the array bounds?
static void solveMaze(){
int nSteps = 0; // Number of steps.
int x = 0; int y = 0; // Starting point.
boolean mazeCompleted = false;
while (!mazeCompleted){
if(x == maze.mazeMatrix.length && y == maze.mazeMatrix.length)
mazeCompleted = true;
else if(maze.mazeMatrix[x+1][y] == 0){ // Move right.
maze.mazeMatrix[x+1][y] = 2;
x++; nSteps++;
}
else if(maze.mazeMatrix[x-1][y] == 0){ // Move left.
maze.mazeMatrix[x-1][y] = 2;
x--; nSteps++;
}
else if(maze.mazeMatrix[x][y+1] == 0){ // Move down.
maze.mazeMatrix[x][y+1] = 2;
y++; nSteps++;
}
else if(maze.mazeMatrix[x][y-1] == 0){ // Move up.
maze.mazeMatrix[x][y-1] = 2;
y--; nSteps++;
}
}
maze.printMatrix();
System.out.println("Maze COMPLETE! - With a total of " + nSteps + " steps.");
}
Tried before with two "for" loops to prevent the out of bounds but I just can't go diagonal in this problem.
You have a pretty crucial bug in your program. You will never reach the end of the maze!
if(x == maze.mazeMatrix.length && y == maze.mazeMatrix.length)
references indices that are out of bounds! It should be
if(x == maze.mazeMatrix.length - 1 && y == maze.mazeMatrix.length - 1)
You also need to check to see whether you can & should move before you try to move there. I.E. :
while (!mazeCompleted){
boolean moveRight = (x + 1 < mazeMatrix.length && maze.mazeMatrix[x+1][y] == 0 ? true : false);
boolean moveLeft = (x - 1 >= 0 && maze.mazeMatrix[x-1][y] == 0 ? true : false);
boolean moveUp = (y + 1 < mazeMatrix[x].length && maze.mazeMatrix[x][y+1] == 0 ? true : false);
boolean moveDown = (y - 1 >= 0 && maze.mazeMatrix[x][y-1] == 0 ? true : false);
And:
else if(moveRight) { // Move right.
maze.mazeMatrix[x+1][y] = 2;
x++; nSteps++;
}
etc. Although it does seem like this is something that should be solved recursively, as if there are any loops in the maze you will end up getting stuck and infinite looping.

How to end my recursion

I need to program a method to solve a maze (2-dimensional array). I need to stay directly left of the wall at all times and my method should end when either I've reached the exit point (which is always at the same position) or when there is no solution possible (and, after running through the maze I'm back at the entry point).
I was able to do all that, no problems, I can visually ensure that it's doing what I want it to do (we've got some other methods from our instructor which output the visuals) and my console debug output is right as well.
This is the relevant code:
public static void main(String[] args) {
maze = generateMaze(10,10);
walk(1,0,0);
}
public static void walk(int x, int y, int direction) {
System.out.println("x = " + x + " y = " + y); //debug output
draw(x,y,maze); //draws current position
if (x == maze.length-1 && y == maze[1].length-2) { //terminate when reached exit
System.out.println("Geschafft!");
return;
}
if (x == 1 && y == 0 && direction == 3) { //terminate when at starting point again (no solution)
System.out.println("Keine Lösung möglich.");
return;
}
if (direction == 0) { //go down
if (maze [x][y+1]) {
walk(x,y,1);
}
walk(x,y+1,2);
}
if (direction == 1) { //go right
if(maze [x+1][y]) {
walk(x,y,3);
}
walk(x+1,y,0);
}
if (direction == 2) { //go left
if(maze [x-1][y]) {
walk(x,y,0);
}
walk(x-1,y,3);
}
if (direction == 3) { //go up
if(maze[x][y-1]) {
walk(x,y,2);
}
walk(x,y-1,1);
}
}
There's just one problem: how do I end my recursion correctly? This is what I get form the console:
x = 1 y = 0
x = 1 y = 1
x = 1 y = 1
x = 1 y = 2
and so on...
x = 8 y = 8
x = 9 y = 8
Geschafft!
x = 8 y = 9
x = 8 y = 9
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10
at maze.MazeSolution.walk(MazeSolution.java:26)
at maze.MazeSolution.walk(MazeSolution.java:39)
and some more of that
I do understand the error, the recursion obviously doesn't end where I want it to and x or y are increased and try to use an index in the array that isn't there.
Why doesn't the recursion end with the return statement, when either of these situations come true:
if (x == maze.length-1 && y == maze[1].length-2) { //terminate when reached exit
System.out.println("Geschafft!");
return;
}
if (x == 1 && y == 0 && direction == 3) { //terminate when at starting point again (no solution)
System.out.println("Keine Lösung möglich.");
return;
}
What do I need to do to end it correctly?
I greatly appreciate your help, show some love for a beginner and tell me what to do.
Add to the beginning
public static void walk(int x, int y, int direction) {
System.out.println("x = " + x + " y = " + y); //debug output
if (x >= 10 || x < 0 || y >= 10 || y < 0) return;
Look at your returns and where you may return to. You can return in the middle of your enclosing function which has other calls to walk, without the guards to ensure they're not called.
I recommend re-implementing your logic; think about having if/else pairs to ensure mutual exclusion.
Why don't you simply return true or false and react on it?
So basically you add to your two end cases return true; for code ended.
if(walk(...)) return true;

Calculating direction based on point offsets

For my tile-based game, I need to calculate direction based on a given point offset (difference between two points). For example, let's say I'm standing at point (10, 4) and I want to move to point (8, 6). The direction I move at is north-west. What would be the best way to calculate this?
Here's me basic implementation in Java.
public int direction(int x, int y) {
if (x > 0) {
if (y > 0) {
return 0; // NE
} else if (y < 0) {
return 1; // SE
} else {
return 2; // E
}
} else if (x < 0) {
if (y > 0) {
return 3; // NW
} else if (y < 0) {
return 4; // SW
} else {
return 5; // W
}
} else {
if (y > 0) {
return 6; // N
} else if (y < 0) {
return 7; // S
} else {
return -1;
}
}
}
Surely it can be optimised or shortened. Any help? Thanks.
I think the easiest to understand way would be making a static array that contains the values for all cases.
// Won't say anything about how much these values make sense
static final int[][] directions = {
{3, 6, 0},
{5, -1, 2}, // -1 for "no direction", feel free to replace
{4, 7, 1}
};
public int direction(int x, int y) {
x = (x < 0) ? 0 : ((x > 0) ? 2 : 1);
y = (y < 0) ? 0 : ((y > 0) ? 2 : 1);
return directions[y][x];
}
Edit: Now it's correct (why are so many languages missing a proper sgn function?)
My answers with if conditions :).
public int direction(int x, int y) {
//0 NE, 1 SE, 2 E, 3 NW, 4 SW, 5 W, 6 N, 7 S, 8 (Same place / Not a direction)
int direction = 0;
if(x < 0){
direction = 3;
}else if(x == 0){
direction = 6;
}
if(y < 0){
direction = direction + 1;
}else if(y == 0){
direction = direction + 2;
}
return direction;
}
define a 2D array to hold all states.
convert x and y to 0, 1 or 2 based on their value (x>0 or x<0 or x ==0)
return the specific index of array.
This is about as short and clean as you can get, if you represent the eight cardinal directions this way, as separate enumerated values. You're choosing between eight distinct return values, so a decision tree with eight leaves is the best you can do.
You might get something a little tidier if you split direction into two components (N-S and E-W), but without knowing more about what you do with direction, we can't know whether that's worth the trouble.
You can receive and return your direction as a Point or something similar (anyway, an (x,y) tuple). So if you're standing in p0 = (10, 4) and want to move to p1 = (8, 6), the result would be (in pseudocode):
norm(p1 - p0) = norm((-2,2)) = (-1,1)
You can calculate the norm of an integer if you divide it by its absolute value. So for a point you calculate the norm of both members. Just bear in mind that (-1,1) is more expressive than 3 and you can operate in an easier fashion with it.
If you need specific operations, you can create your own Java Point class or extend the existing ones in the library.

Categories