I'm working on assignment now for my comp class and am currently getting the hang of dynamic programming. Our current task is that we are given a matrix of size m x n, where either m or n is guaranteed to at least be 2. This matrix is filled with various values that dictate how many "steps" we may move from said position in any cardinal direction, with the goal being that we start at index (0,0) and have to make our way to index (n-1,m-1), or, better put, the bottom right corner of the matrix, in the smallest amount of trips as possible. If such a path is not possible, we must return -1. Here's an example:
1
2
7
5
6
3
The smallest amount of jumps required to get from the top left to the bottom right is 2, since we start at (0,0), which, with value of 1, means we can move 1 step in any direction. We then go to (0,1), which has a value of 2, which we'll use to "step" two positions down into (2,1), which is the bottom right corner. Overall, this journey took two trips: the one from (0,0) to (0,1), and then another from (0,1) to (2,1). It is worth nothing that at position (0,0), I could have also gone down to (0,1), but that wouldn't have resulted in anything useful.
I'm taking a dynamic programming approach, with a table to store previously calculated values and cut down runtime, with a separate table to let me know if I've calculated that position or not. My code is as follows:
private static int [][] dpArray;
private static int [][] solveState;
private static int rowDest;
private static int colDest;
public static int min_moves(int[][] board) {
rowDest = board.length - 1;
colDest = board[0].length - 1;
solveState = new int[rowDest + 1][colDest + 1];
dpArray = new int[rowDest + 1][colDest + 1];
int ans = minMoveRecur(0,0, board);
if (ans == 100000000) {
return -1;
}
private static int minMoveRecur(int row, int col, int[][] board) {
if ((row == rowDest) && (col == colDest)) {
return 0;
}
if ((row < 0) || ( rowDest < row) || (col < 0) || (colDest < col)) {
return 100000000;
}
if (solveState[row][col] == 1) {
return dpArray[row][col];
}
solveState[row][col] = 1;
int up = row - board[row][col];
int down = row + board[row][col];
int right = col + board[row][col];
int left = col - board[row][col];
int vertBest = Math.min(minMoveRecur(up,col,board),minMoveRecur(down,col,board));
int horizBest = Math.min(minMoveRecur(row,right,board),minMoveRecur(row,left,board));
dpArray[row][col] = 1 + Math.min(vertBest,horizBest);
return dpArray[row][col];
}
I take have a recursive relation that finds which path resulted in the minimum number of jumps, but I have been getting the wrong answer for one of test boards I have, where
int [][]board = {{2},{4},{2},{0},{4},{4},{3},{5},{1},{3}};
is supposed to take 4 jumps { (0,0) -> (2,0) -> (4,0) -> (8,0) -> (9,0) }, but I keep getting 2 jumps. I've debugged a few times, and it appears that the issue has to do with the vertBest and horizBest not getting the correct values from the recursive calls. It seems that vertBest's value is always 0, up until the very end where it is 1, which then is added to the 1 from the initial recursive call's dpArray[row][col] = 1 + Math.min(vertBest,horizBest); to be 2. It doesn't seem to be adding on the +1 from its earlier calls.
Can anyone help shed some light on what's going wrong here?
When you try to go up, in the minMoveRecur(up,col,board) call, solveState[row][col] = 1 however you have not updated dpArray[row][col] yet.
As a result since solveState[row][col] = 1 and dpArray[row][col], 0 is returned (due to the 3rd if condition) and 1 is added to it.
Related
Background
I had an interview today and I was asked the following question.
You are given a grid.
int [][] grid =
{
{0,0,0,2,5},
{0,0,0,1,5},
{0,1,1,1,1},
{2,0,0,0,0}
};
You start from the bottom left off the grid. You can only go up and right. The idea is to get to the TOP right corner. You are to take the path that will get you the most Value.
The output for the above would be 16
My solution
public static int getPathMaxSum(int [][] grid){
int row = grid.length-1;
int col = 0;
int currentSum = grid[row][col];
return getMax(grid,currentSum,row,col);
}
public static int getMax(int [][] grid,int sum,int row,int col){
if((isTopRight(grid,row,col)) || (!isValid(grid,row,col))){
return sum;
}else{
sum = sum + grid[row][col];
return Math.max(getMax(grid,sum,row-1,col),getMax(grid,sum,row,col+1));
}
}
public static boolean isTopRight(int [][] grid, int row, int col){
return row == 0 && col == grid[row].length-1;
}
public static boolean isValid(int [][] grid, int row, int col){
return (row >= 0 && row < grid.length) && (col >= 0 && col < grid[row].length);
}
I am trying to solve this recursively. I figure that i have 2 possible choices to make at every position and i want to get the max of the two choices but for some reason I am not able to get the correct output.
I have two helper functions that check if my position is valid meaning inside the grid and also if i have hit the top right and if i have then i hit my base case.
I would love inputs to see where i went wrong.
You don't need a sum parameter in your method.
I assume you already understand how recursion-topdown approach for this problem.
But again just for the sake of completeness, the basic formula is:
You start with a cell at row, col get its value and then either you look to UP (row-1, col) or RIGHT (row, col+1).
So the result is going to be:
grid[row][col] + Math.max( getMax( row-1, col, grid ), getMax( row, col+1, grid ) )
Base conditions:
a) If it is top right i.e. the destination, you don't need to recurse you just return the value at that cell.
b) If it is an invalid cell like you have written in your isValid method, you need to return Integer.MIN_VALUE because you could have a negative value in your other cells and you want them to be maximum.
So your getMax function needs to be:
public static int getMax(int [][] grid,int row,int col){
if (isTopRight(grid,row,col)) {
return grid[row][col];
} else if (!isValid(grid,row,col)){
return Integer.MIN_VALUE;
} else {
return grid[row][col] + Math.max(getMax(grid,row-1,col),getMax(grid,row,col+1));
}
}
You can see working example here
EDIT: Answer to the edited version of your code
Issues with your new solution:
int currentSum = grid[row][col]; and sum = sum + grid[row][col];
The sum is initialized with the value in the bottom left corner and in the initial call of getMax() the same value is added again. This is not what it should be like. Just start the sum with 0, adding will be done by getMax().
if((isTopRight(grid,row,col)) || (!isValid(grid,row,col))) then return sum;
For invalid positions this will work (see restrictions below my code), but not for the top right corner (since we haven't added the value of the corner yet). Thus pull the two conditions apart and only return directly on invalid positions. On any other position first add the value and then, if you reached the "goal", return the sum. Otherwise return the maximum of "going right" and "going up" (the recursive call is correct now).
Fixing these issues and implementing your example, I derived the following code:
public class Pathfinder {
public static void main(String... args) {
int [][] grid = {
{0,0,0,2,5},
{0,0,0,1,5},
{0,1,1,1,1},
{2,0,0,0,0}
};
System.out.println(getPathMaxSum(grid));
}
public static int getPathMaxSum(int[][] grid) {
int row = grid.length - 1;
int col = 0;
return getMax(grid, 0, row, col);
}
public static int getMax(int[][] grid, int sum, int row, int col) {
if(!isValid(grid, row, col))
return sum;
sum = sum + grid[row][col];
if(isTopRight(grid, row, col))
return sum;
return Math.max(getMax(grid, sum, row - 1, col), getMax(grid, sum, row, col + 1));
}
public static boolean isTopRight(int[][] grid, int row, int col) {
return row == 0 && col == grid[row].length - 1;
}
public static boolean isValid(int[][] grid, int row, int col) {
return (row >= 0 && row < grid.length) && (col >= 0 && col < grid[row].length);
}
}
Note, that this version will work for any grid (as long as the stack is big enough and we are not dealing with too large numbers, e.g. we won't get any integer overflow) if all entries are non-negative. Anyways, a grid with negative entries can be manipulated in such a way, that the best path will be found by this algorithm and the solution can be easily "translated" back to the original grid (just subtract the smallest value from every entry).
ANSWER TO THE ORIGINAL CODE
I see multiple issues with your code:
isValid(grid,row+1,col) and sum1 = grid[row+1][col];
You are trying to add 1 to the row, but you started (correctly) with int row = grid.length-1;. Adding 1 will give you an invalid position, thus the first branch will never be executed. Instead, you will need to subtract 1 from the row to "go up".
sum = sum + Math.max(sum1,sum2);
This changes sum, but you cannot see, in which direction you moved. And directly afterwards ...
getMax(grid,sum,row+1,col); and getMax(grid,sum,row,col+1);
... you do the recursive calls with the new, maximum sum, but from both spots. To get a correct solution, you should call them with the value, their direction represents. Note also, that row+1 needs to be replaced by row-1 here as well.
return sum;
You now return this maximum sum, but completely ignoring the returns of your recursive calls. You should instead compare their returns and return yourself the higher value of both.
Bactracking vs. Dynamic Programming
Your algorithm should work in general and is sufficient for small instances of the problem, but not for bigger ones (since it will make 2 recursive calls for every step and you have 2*(n-1) steps.. resulting in exponential runtime). An alternative approach with quadratic runtime would be to go backwards through the field and choose the best way by looking just one field right or up and adding the value of the current field to the maximum of this. Just start in the top right corner and go left, row by row from right to left.
I was reading this program that I saw in class relating to a checkers game this is the method that is called getup.
int rowUp = row-1;
if(column == 0 && row != 0)
{
for(int i = column; i < column+2; i++)
{
if(gameData[column][row] != 0 && gameData[i][rowUp] != 0)
{
if(canJump(column, row, i, rowUp) == true) {
int jumpCol = jumpPos(column, row, i, rowUp)[0];
int jumpRow = jumpPos(column, row, i, rowUp)[1];
availablePlays[jumpCol][jumpRow] = 1;//makes it available
}
}
else if(baseGameData[i][rowUp] == 1 && gameData[i][rowUp] == 0)
availablePlays[i][rowUp] = 1;
}
}
the Part that I dont understand is:
int jumpCol = jumpPos(column, row, i, rowUp)[0];
int jumpRow = jumpPos(column, row, i, rowUp)[1];
I really dont get what the col row i and row up parameters are and what the [0] or [1] mean. and how can this even be assigned to an int
The int jumpCol can be assigned because its the position of the spot in the checkers game. For example, if you had a row of names (Alex, Allen, George, Greg). REMEMBER: THE FIRST ONE OF AN ARRAY IS ALWAYS 0. In programming, we could assume that Alex would be at position 0 (or [0]), Allen would at [1], George would be position [2], and Greg would be position [3]. Technically there would still be 4 (0,1,2,3) but we start off with 0 instead of 1. So, you are technically assigning the position of the item. In our small example, you would be assigning the location of the item instead of the actually item. Sorry, that might of sounded a bit confusing. To shorten it, you are assigning the integer to Allen. But in reality your actually assigning the integer to the location. So because Allen is in [1] (position 1) your integer would have the value of 1, instead of "Allen.
Hope this helped.
I am making connect 4 AI, except the game continues until all 42 spaces are filled.
Score is kept by every 4 in a row gets 1 point.
public int[] Max_Value(GameBoard playBoard, int depth){
GameBoard temp = new GameBoard(playBoard.playBoard);
int h = 0, tempH = 999, tempCol=0;
int myDepth = depth - 1;
int[] tempH2 = new int[2];
boolean noChildren = true;
if(myDepth != -1){
for(int i = 0; i < 7; i++){
if(temp.isValidPlay(i)){
count++;
temp.playPiece(i);
noChildren = false;
tempH2 = Min_Value(temp, myDepth);
if(tempH2[1] < tempH){
tempH=tempH2[1];
tempCol = i;
}
temp.removePiece(i);
}
}
}
int[] x = new int[2];
if(noChildren){
h = temp.getHeuristic();
}
else{
h = tempH;
x[0]=tempCol;
}
x[1]=h;
return x;
}
public int[] Min_Value(GameBoard playBoard, int depth){
GameBoard temp = new GameBoard(playBoard.playBoard);
int h = 0, tempH = -999, tempCol=0;
int myDepth = depth - 1;
int[] tempH2 = new int[2];
boolean noChildren = true;
if(myDepth != -1){
for(int i = 0; i < 7; i++){
if(temp.isValidPlay(i)){
count++;
temp.playPiece(i);
noChildren = false;
tempH2 = Max_Value(temp, myDepth);
if(tempH2[1] > tempH){
tempH=tempH2[1];
tempCol = i;
}
temp.removePiece(i);
}
}
}
int[] x = new int[2];
if(noChildren){
h = temp.getHeuristic();
}
else{
h = tempH;
x[0]=tempCol;
}
x[1]=h;
return x;
}
I feel like I just stumbled through everything, and it feels like terrible code. However, I have never attempted anything like this before, and would appreciate any input. I can't tell where I am going wrong. My evaluation function just gives 1 point for each 4 in a row it can find for any given state. The main function calls the Min_Value function to start things off with a depth of 10.
I am attempting to return the column as well as the value of the heuristic. I hope I have provided enough information. Thanks for any insight.
Allright, after implementing the methods not shown (like evaluation, playmove, remove etc.) I was able to debug this. Assuming that these functions are implemented in some correct way in your version, the mistake is that you never actually call the evaluation function if depth is -1:
You have this:
[...]if(myDepth != -1)
{/*restofthecode*/}[...]
But what you need is something like this:
[...]if(myDepth == -1)
{
return temp.getHeuristic();
}
/*restofthecode*/
[...]
That way, whenever you reach depth -1 (a leaf in your minimax tree), the board will be evaluated and the value returned (which is excactly what you need in minimax).
Do this modification in both parts (min and max) and everything shuold be allright. If there are other problems, feel free to ask.
Even though it isn't stated in the question, I think you are not getting good moves from your search, right?
Without looking through your while code, I can already say that your program will only work during the last 10 moves of the game (last 10 empty fields or forced win in 10). Otherwise, your program will return either the last or the first move it evaluated. That is because of your evaluation function, where you only handle a win (respectively 4 in a row), but not 2 in a row, traps, 3 in a row, etc.). It will think of all moves as equal if it can't force a win.
This is a problem, because starting with an empty field, a win can only be forced by the starting player, and just with the 2nd last piece to be placed on the board. (In your version 4 in a row forced).
And since your searchdepth (10) is smaller than the maximum game moves (42), your program will always play its first move.
If the rest of your algorithm is correctly implemented, you can fix this by simply improve your evaluation function, so that it can differ between "good" and "bad" game positions.
The nature of this problem has changed since submission, but the question isn't fit for deletion. I've answered the problem below and marked it as a community post.
I'm writing a recursive path-navigating function and the final piece I need involves knowing which cell you came from, and determining where to go next.
The Stage
You are given a 2d array where 0's denote an invalid path and 1's denote a valid path. As far as I know, you are allowed to manipulate the data of the array you're navigating, so I mark a traveled path with 2's.
The Goal
You need to recursively find and print all paths from origin to exit. There are four mazes, some with multiple paths, dead ends, or loops.
I've written code that can correctly handle all three cases, except the method for finding the next path is flawed in that it starts at a fixed location relative to your current index, and checks for a travelled path; If you encounter it, it's supposed to retreat.
While this works in most cases, it fails in a case when the first place it checks happens to be the place you came from. At this point, it returns out and ends prematurely.
Because of this, I need to find a way to intelligently start scanning (clockwise or anti-clockwise) based on where you came from, so that that place is always the last place checked.
Here is some code describing the process (note: edge cases are handled prior to this, so we don't need to worry about that):
private static void main()
{
int StartX = ;//Any arbitrary X
int StartY = ;//Any arbitrary Y
String Path = ""; //Recursive calls will tack on their location to this and print only when an exit path is found.
int[][] myArray = ;//We are given this array, I just edit it as I go
Navigator(StartX, StartY, Path, myArray);
}
private static void Navigator(int locX, int locY, String Path, int[][] myArray)
{
int newX = 0; int newY = 0;
Path = Path.concat("["+locX+","+locY+"]");
//Case 1: You're on the edge of the maze
boolean bIsOnEdge = (locX == 0 || locX == myArray.length-1 || locY == 0 || locY == myArray[0].length-1);
if (bIsOnEdge)
{
System.out.println(Path);
return;
}
int[][] Surroundings = surroundingsFinder(locX, locY, myArray);
for (int i = 0; i <= 7; i++)
{
//Case 2: Path encountered
if (Surroundings[0][i] == 1)
{
myArray[locX][locY] = 2;
newX = Surroundings[1][i];
newY = Surroundings[2][i];
Navigator(newX, newY, myArray, Path);
}
//Case 3: Breadcrumb encountered
if (Surroundings[0][i] == 2)
{
myArray[locX][locY] = 1;
return;
}
}
}
//generates 2D array of your surroundings clockwise from N to NW
//THIS IS THE PART THAT NEEDS TO BE IMPROVED, It always starts at A.
//
// H A B
// G - C
// F E D
//
static int[][] surroundingsFinder(int locX, int locY, int[][] myArray)
{
int[][] Surroundings = new int[3][8];
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
}
}
//Can be done simpler, is done this way for clarity
int xA = locX-1; int yA = locY; int valA = myArray[xA][yA];
int xB = locX-1; int yB = locY+1; int valB = myArray[xB][yB];
int xC = locX; int yC = locY+1; int valC = myArray[xC][yC];
int xD = locX+1; int yD = locY+1; int valD = myArray[xD][yD];
int xE = locX+1; int yE = locY; int valE = myArray[xE][yE];
int xF = locX+1; int yF = locY-1; int valF = myArray[xF][yF];
int xG = locX; int yG = locY-1; int valG = myArray[xG][yG];
int xH = locX-1; int yH = locY-1; int valH = myArray[xH][yH];
int[][] Surroundings = new int[3][8];
Surroundings[0][0] = valA; Surroundings[1][0] = xA; Surroundings[2][0] = yA;
Surroundings[0][1] = valB; Surroundings[1][1] = xB; Surroundings[2][1] = yB;
Surroundings[0][2] = valC; Surroundings[1][2] = xC; Surroundings[2][2] = yC;
Surroundings[0][3] = valD; Surroundings[1][3] = xD; Surroundings[2][3] = yD;
Surroundings[0][4] = valE; Surroundings[1][4] = xE; Surroundings[2][4] = yE;
Surroundings[0][5] = valF; Surroundings[1][5] = xF; Surroundings[2][5] = yF;
Surroundings[0][6] = valG; Surroundings[1][6] = xG; Surroundings[2][6] = yG;
Surroundings[0][7] = valH; Surroundings[1][7] = xH; Surroundings[2][7] = yH;
return Surroundings;
}
Can anyone help me with this? As you can see, surroundingsFinder always finds A first, then B all the way to H. This is fine if and only if you entered from H. But if fails on cases where you entered from A, so I need to make a way to intelligently determine where to start finding. Once I know this, I can probably adapt the logic so I no longer use a 2D array of values, as well. But so far I can't come up with the logic for the smart searcher!
NOTE: I am aware that Java does not optimize middle-recursion. It seems impossible to get tail recursion working for a problem like this.
The Solution
The initial goal was to print, from start to end, all of the paths that exit the array.
An earlier rendition of the script wrote "0" on treaded locations rather than "2", but for some reason I imagined that I needed the "2" and I needed to differentiate between "treaded path" and "invalid path".
In fact, due to the recursive nature of the problem, I discovered that you can in fact solve the problem writing only 0's as you go. Also, I no longer needed to keep track of where I came from and instead of checking clockwise over a matrix, I was iterating from left to right down the 3x3 matrix surrounding me, skipping my own cell.
Here is the completed code for such a solution. It prints to console upon finding an exit (edge) and otherwise traces itself around the maze, complete with recursion. To start the function, you are given a square 2D array of 0's and 1's where 1 is a valid path and 0 is invalid. You are also given a set of coordinates where you are "dropped in" (locX, locY) and an empty string that accumulates coordinates, forming a path that is later printed out (String Path = "")
Here is the code:
static void Navigator(int locX, int locY, int[][] myArray, String Path)
{
int newX = 0;
int newY = 0;
Path = Path.concat("["+locX+","+locY+"]");
if ((locX == 0 || locX == myArray.length-1 || locY == 0 || locY == myArray[0].length-1))
{//Edge Found
System.out.println(Path);
pathCnt++;
myArray[locX][locY] = 1;
return;
}
for (int row = -1; row <= 1; row++)
{
for (int col = -1; col <= 1; col++)
{
if (!(col == 0 && row == 0) && (myArray[locX+row][locY+col] == 1))
{ //Valid Path Found
myArray[locX][locY] = 0;
Navigator(locX+row, locY+col, myArray, Path);
}
}
}
//Dead End Found
myArray[locX][locY] = 1;
return;
} System.out.println(Path);
pathCnt++;
swamp[locX][locY] = 1;
return;
}
for (int row = -1; row <= 1; row++)
{
for (int col = -1; col <= 1; col++)
{
if (!(col == 0 && row == 0) && (swamp[locX+row][locY+col] == 1))
{ //Valid Path Found
swamp[locX][locY] = 0;
Navigator(locX+row, locY+col, swamp, Path);
}
}
}
//Dead End Found
swamp[locX][locY] = 1;
return;
}
As you may determine yourself, every time we "enter" a cell, we have 8 neighbors to check for validity. First, to save on run time and to avoid going out of the array during our for loop (it can't find myArray[i][j] if i or j point it outside, and it will error out), we check for edges. Since we're given the area of our swamp we use a truth comparison statement that essentially says ("(am I on the top or left edge?) or (am I on the bottom or right edge?)"). If we ARE on an edge, we print out the Path we're holding (thanks to deep copy, we have a unique copy of the original Path that only prints if we're on an edge, and includes our full set of coordinates).
If we aren't on an edge, then we start looking around us. We start at top left and move horizontally to bottom right, with a special check to make sure we're not checking where we're standing.:
A B C
D . E
F G H
This loop checks only for 1's and only calls the function up again should that happen. Why? Because it is the second-to-last case. There is only one extra situation that will occur, and if we reach the end of the function it means we hit that case. Why write extra code (checking for 0's to specifically recognize it?
So, as I just mentioned, if we exit the for loop, it means we didn't encounter any 1's at all. It means we're surrounded by zeros! It means we've hit a dead end, and that means that all we have to do is error our away out of that instance of the function, ergo the final return;.
All in all, the final function is simple. But coming from no background and having to realize the patterns and meanings of these cases, and after several failed attempts at this, it can take quite a bit of work. I was several days at work on perfecting this.
Happy coding, Everyone!
Your issue seems to be with:
if (Surroundings[0][i] == 2)
{
myArray[locX][locY] = 1;
return;
}
Perhaps this should be changed to:
if (Surroundings[0][i] == 2)
{
// not sure why you need this if it's already 1
myArray[locX][locY] = 1;
// go to next iteration of the "i" loop
// and keep looking for next available path
continue;
}
Your recursive method will automatically return when none of the surrounding cells satisfy the condition if (Surroundings[0][i] == 1).
PS: It's conventional to name your variables using small letter as the first character. For example: surroundings, path, startX or myVar
I am trying to rebuild this algorithm:
http://courses.csail.mit.edu/6.006/fall10/lectures/lec02.pdf
(Page 14 "Algorithm II")
(found this with google, unfortunatly i am not at MIT :) and this is not homework)
Which is:
•Pick middle column (j=m/2)
•Find global maximum a=A[i,m/2]in that column
(and quit if m=1)
•Compare a to b=A[i,m/2-1]and c=A[i,m/2+1]
•If b>a then recurse on left columns
•Else, if c>a then recurse on right columns
•Else a is a 2D peak!
What i have is this:
trimmed is a vector which holds my frequencies of size (blockSizeSmall-minBlockSize).
So its a 2D Matrix with trimmed.size() columns and (blockSizeSmall-minBlockSize) rows.
For simpliciticy i save the peaks in 2 int vectors vector<int> peaksrow and peakscolumn.
Whats wrong there ?
I dont get what
"Find global maximum a=A[i,m/2]in that column (and quit if m=1)"
should result in.
public void findPeaks() {
for (int column = trimmed.size() / 2; column < trimmed.size();) {
int globalmax = 0;
for (int row = 0; row < (blockSizeSmall - minBlockSize); row++) {
if (trimmed.elementAt(column).reducedFreqs[row] > globalmax) {
globalmax = row;
//find globalmax in row
}
}
if (globalmax == 0) {
break; //<- ???
} else {
if (column - 1 >= 0 && column + 1 < trimmed.size()) {
//stay in bounds
if (trimmed.elementAt(column - 1).reducedFreqs[globalmax] > globalmax) {
column--;
//if element at left side is > globalmax, recurse on column--;
} else if (trimmed.elementAt(column + 1).reducedFreqs[globalmax] > globalmax) {
column++;
//if element at right side is > globalmax, recurse on column++;
} else {
//if globalmax is higher than right or left element i have a peak
peaksrown.add(globalmax);
peakscolumnn.add(column);
Log.e(TAG, "" + peaksrown.size());
}
}else{
//what to do when out of bounds ?? break ??
//if i break here, how can i be sure the algorithm
//went to both sides(column=0 and column=max) ??
//just tried with break here, still infinit loop
}
}
}
}
It just loops endless.
You don't seem to understand the concept of recursion so I would advise you look it up. Here's an algorithm in C# for reference, not tested beyond the one example in the paper but it should work. I ignored the "and quit if m=1" part as I don't think that's needed. Note how the function Peak() calls itself from within itself, but with changed parameters.
static void Peak(int[,] map, int left, int right)
{
// calculate middle column
int column = (right + left) / 2;
// get max row in column
int arow = 0;
for (int row = 0; row < map.GetLength(0); row++)
if (map[row, column] > map[arow, column])
arow = row;
int a = map[arow, column];
// get left value
int b = 0;
if (column - 1 >= left) b = map[arow, column - 1];
// get right value
int c = 0;
if (column + 1 <= right) c = map[arow, column + 1];
// if left is higher, recurse left
if (b > a) Peak(map, left, column - 1);
// else if right is higher, recurse right
else if (c > a) Peak(map, column + 1, right);
// else, peak
else Console.WriteLine("Peak: " + arow + " " + column + " " + a);
}
static void Main(string[] args)
{
int[,] map = { {12, 8, 5},
{11, 3, 6 },
{10, 9, 2 },
{ 8, 4, 1 } };
Peak(map, 0, 2);
Console.ReadLine();
}
I think this algorithm has a subtle bug. A local maximum in the right half is not necessarily a local maximum in the entire array (e.g., when the local max in the right half is on its left border). So, although there is a local max (of the entire array) in the right half (assuming right is higher), the recursive call will not necessarily find it.