Brute force chromatic number in Java - java

This is a brute force attempt at the chromatic number of a matrix. It seems to work in the sense that it gives me the correct number of colors required but instead of 1,2,3,4 it will display 1,2,3,6. For some reason even if the matrix is possibly successful with fewer colors it will still fail and keep going to the max number. Is there a reason why it continues to fail?
"n" is the max number of colors. "v" is the vertex, and "m" is the number of currently used colors.
pseudo code:
http://i42.tinypic.com/deoc2u.jpg
static int color(){
int i;
for(i = 1; i <= n; i++)
{
if(color(0,i)){
return i;}
}
return i;
}
static boolean color(int v, int m) {
if(v > n-1)
return true;
else
{
for(int i = 1; i <= m; i++)
{
boolean match = false;
q[v] = i;
for(int j = 0; j < n; j++)
{
if(input[v][j] == 1)
{
if(q[v] == j+1)
match = true;
}
}
if(match == false)
{
if(color(v+1,m))
return true;
}
}
q[v] = 0;
return false;
}
}
sample output:
File Name: file1
Input
6
0 1 1 0 1 1
1 0 1 1 1 1
1 1 0 1 0 1
0 1 1 0 1 1
1 1 0 1 0 1
1 1 1 1 1 0
1 failed
2 failed
3 failed
4 failed
5 failed
Colors:
1 2 3 1 3 6

Gah, I should be asleep! But I can't count the number of times I've put off an assigment to the absolute last possible moment, so I'm feeling sympathetic regarding your deadline.
It's not really a "brute-force" approach, since that would actually come down to trying each and every possible node coloring combination and check which ones don't conflict. Your approach is a heuristic known as greedy coloring. It can find optimal results but can also yield an arbitrarily bad solution. That said, I've tried manually going through the sample input you've provided (thank you, Microsoft Paint) and following that algorithm the result should indeed be 4 when starting from vertex 0.
So here's what I believe might be wrong with your code. In the following extract...
if(input[v][j] == 1)
{
if(q[v] == j+1)
match = true;
}
You seem to be comparing the color of the current vertex (which will just be i anyway) to a vertex index, rather than the color of that other vertex. I think you'll need to alter the inner test to...
if(i == q[j])
or, if you wish (won't make a difference)...
if(q[i] == q[j])
Also, you're doing a bit too many checks. Vertex 0 can be assigned color 1. Vertex 1 then needs to be checked against vertex 0 if it's adjacent. Vertex 2 needs to be checked against 0 and 1 if they're adjacent, and so on. You're checking against vertices that couldn't have been assigned a color yet. So don't limit j to n but limit it to your current vertex v.
Finally, using a construct like if(match == false) is rather confusing and not necessary. Just use if(!match) instead.
Hope this helps. If you're still stuck and I happen to catch the comments in time, I can provide more pointers.

Related

Counting occurrences of an array element - Index out of bounds error but the index number and out of bounds length are the same number?

So I'm having some issues with code I'm writing for an assignment and it's kinda driving me crazy. It's my first semester and I've never done coding before, so I know I still have heaps to learn. Anyways, the issues:
I'm having two problems which could be related but I'm not 100% sure. I'm getting this error:
'Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 125 out of bounds for length 125.'
Which points to the following section of code (Commented on specific line):
public static String gradesDistn() {
String gradeDistn = "0";
//Sort the above letterGrade array
Arrays.sort(letterGrade);
//This loop counts each occurrence of an element in the letterGrade array.
for (int i = 0; i < letterGrade.length - 1; i++) {
int count = 0;
for(int j = i + 1; j < letterGrade.length; j++) {
if (letterGrade[i] == letterGrade[j])
count++;
System.out.println (gradeDistn = letterGrade[i] + ": " + count); //THIS IS THE ERROR LINE.
i += (count-1);
}
}
return gradeDistn;
I can post the full code if additional context is needed. Essentially I'm am trying to count the occurrences of each letter grade (A, B, C, D, E and F) which are stored in an array. Each occurrence is based off of another array which stores number marks and is randomly generated. So the results should look something like this:
A: 6
B: 10
C:20
D: 9
E: 3
F: 1
instead I'm getting (copied from console):
A: 1
A: 2
A: 3
A: 4
B: 5
B: 6
B: 7
B: 8
B: 9
B: 10
B: 11
C: 11
C: 11
D: 11
D: 11
F: 11
C: 20
D: 9
E: 3
F: 1
I've spent so long looking at these code and trying to make it work, I feel like I'm am blind to the potentially obvious issues with it. Any help on this 2 issues would be really appreciated!
Also of note: The assignment requires a bunch of super specific methods such as this so that can't be changed, addition classes can not be used etc.
For this answer, I'm going to put aside the question of ArrayIndexOutOfBoundsException and offer guidance on how to generate a frequency distribution.
You are going to want a set of counters. Each counter will represent a range of values. To start, you should decide what range each counter will represent. Too fine a resolution, and your frequency distribution will not be very useful. For example, if your data is 100 meter sprint times for high school boys, and each counter represents an interval of 1/10,000 of a second, unless your sample size is very large, your frequency distribution would have a lot of values of '1' and '0'. You might want to separate by 1/10 of a second, 1 second, or 2 seconds, depending on how much variation there is in the boys' times.
But, if your data is species of farm animals, it would be fine to have a separate counter for each possible value.
So, determine how many counters you will need. What is the range of possible values? How closely do you want to group them?
Next, you will want a means of linking a particular value to a particular counter. In some cases, a little math can be used. In other cases, an if ... else if ... chain or a switch block is useful.
For the first example, I want to analyze daily high temperatures. I decide to group by 10 degrees Fahrenheit. I could decide on 5 degrees, 7 degrees, or some other interval. It could even be irregular intervals. But, keeping it regular and going by 10 degrees makes the example easier to follow.
Having settled on grouping by 10 degrees, I next want to decide the maximum and minimum. I'll pick -19 as the coldest, and 119 as the hottest. But, I want to allow for occurrences outside of that range. So, to hold the count, I will want an array of 15 counters.
Next, I will want a means of "translating" a temperature measurement to an array index. I use the int variable k for that in the following code. To make it easier to follow, I broke the calculation into 4 lines and then used the result as a subscript:
public static int [] tempFreqDist (WeatherStats [] daily) {
int [] count = new int [15]; // java initializes to zeros
int k;
for (int dIdx = 0; dIdx < daily.length; ++ dIdx) {
k = daily [dIdx].getHighTemp();
k = Math.max (k,-20);
k = Math.min (k,120);
k = k/10 + 2;
count [k]++;
}
return count;
}
That's it! One loop, and no sorting.
We want to group temps of -20 and colder together, regardless of how far below -20. So, we use Math.max. Similarly, we group temps of 120 and hotter by using Math.min. Next, divide by our grouping factor, and adjust the result so the lowest has 0 for the subscript value.
So, the result is the elements of count correspond to the temperature ranges: 0 ➔ -20 and colder; 1 ➔ "teens" (10 to 19) below zero; 2 ➔ single digits below zero; 3 ➔ zero and single digits above; 4 ➔ teens above zero; 5 ➔ twenties, ..., 14 ➔ teens above 100; 14 ➔ 120 and above.
But, suppose the 'width' of categories was irregular? One possibility is that you could use a chain of if ... else:
int t = daily [dIdx].getHighTemp();
if (t <= -20) k = 0;
else if (t <= -13) k = 1;
else if (t <= 0) k = 2;
else if (t <= 15) k = 3;
else if (t <= 28) k = 4;
and so on.
Another example counts animals you might see on a farm.
You can do that with an if ... else if ... chain:
public int[] animalFD (String [] species) {
int [] count = new int [6];
// 0 ➔ cattle, 1 ➔ pig, 2 ➔ sheep,
// 3 ➔ goat, 4 ➔ duck, 5 ➔ horse
...
for (int m = 0; m < species.length; ++m) {
if (species[m].equals("cow") count[0]++;
else if (species[m].equals("pig") count [1]++;
else if ...
But, for something like this, I prefer switch to if ... else chain:
public static int [] animalFD (String [] species) {
int [] count = new int [6];
for (int m = 0; m < species.length; ++m) {
switch (letterGrade [m]) {
case "cow":
count[0]++;
break;
case "pig":
count [1]++;
break;
case "sheep":
count [2]++;
break;
case "goat":
count [3]++;
break;
...
Here is a "trick" you can use to easily convert a letter to an index. Recall that a char is essentially a integer primitive: You can do numeric calculations on it.
char letter;
int idx;
...
if (letter >= 'A' && letter <= 'Z') {
idx = letter - 'A'; // result is zero to 25
...
This takes advantage of the fact that the letters A to Z are consecutive in character set encoding. However, that isn't universal. EBCDIC, for example, has non-letter characters between I and J, and between R and S, IIRC.

Making a island large leetcode - spotting mistake Java

I am working on LeetCode problem 827. Making A Large Island:
You are given an n x n binary matrix grid. You are allowed to change at most one 0 to be 1.
Return the size of the largest island in grid after applying this operation.
An island is a 4-directionally connected group of 1s.
Example 1:
Input: grid = [[1,0],[0,1]]
Output: 3
Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3.
My solution fails for the following test case:
[[1,1,0],[0,0,0], [1,1,0]]
The output of my code is 3, but 5 is expected.
Here is my code:
class Solution {
public int largestIsland(int[][] grid) {
int n=grid.length;
int max=0;
boolean hasZero=false;
boolean[][] visited = new boolean[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(grid[i][j]==0){
grid[i][j]=1;
max=Math.max(max,area(grid,n,i,j,visited));
grid[i][j]=0;
// visited[i][j]=false;
hasZero=true;
}
}
}
return hasZero?max:n*n;
}
private int area(int[][] grid, int n, int i, int j, boolean[][] visited){
if(i<0 || i>n-1 || j>n-1 || j<0 || grid[i][j]==0 || visited[i][j])
return 0;
visited[i][j]=true;
int a1 = area(grid,n,i+1,j,visited);
int a2 = area(grid,n,i,j+1,visited);
int a3 = area(grid,n,i-1,j,visited);
int a4 = area(grid,n,i,j-1,visited);
return 1+a1+a2+a3+a4;
}
}
This solution is O(N^4) and I know other, more efficient working solutions, but I'm not able to spot what's wrong with my attempt.
Could someone spot what is wrong?
The problem is that after you have marked an island as visited, it can no longer play a role in a better connection.
For instance, your failing test case:
[[1, 1, ],[0, 0, 0],[1, 1, 0]]
...can be depicted as:
1 1 0
0 0 0
1 1 0
Your code will first try this (changing the value in brackets):
1 1(1)
0 0 0
1 1 0
... and mark those as visited (I'll mark those with "v"):
v v v
0 0 0
1 1 0
...and so it finds 3 for max.
Then it will continue with finding the following:
v v v
(1)0 0
1 1 0
This will lead to a value of 3, which does not improve the previous value for max. But this is wrong, because it really connects with another island that you had marked visited. It should have found this:
1 1 0
(1)0 0
1 1 0
... which is 5.
As you already found working algorithms, I suppose this answers your question.

Find max matching 3 Triangular numbers

It's well known that any positive number can be expressed through at most 3 Triangular numbers. (
https://oeis.org/A000217 )
Example:
11 := 10 + 1
12 := 10 + 1 + 1
13 := 10 + 3
14 := 10 + 3 + 1
15 := 15
I am searching the representation of the positive number n through at most 3 possible Triangular summands. There can exist more than one representation of n. I am interested in the one with the greatest summands.
Is there a more effective way than 2 decreasing for and 1 increasing for loops to find the summands?
public void printMaxTriangularNumbers(int n){
int[] tri = createTriangularNumbers(1000);
lbl: for(int i = tri.length-1; ; i--){
int tmp = n - tri[i];
if(tmp == 0){
System.out.println(tri[i]);
break;
}
for(int j=i; j>0; j--){
int tmp2 = tmp - tri[j];
if(tmp2 ==0){
System.out.println(tri[i]);
System.out.println(tri[j]);
break lbl;
}
for(int k=1; k <= j;k++){
if(tmp2 - tri[k] == 0){
System.out.println(tri[i]);
System.out.println(tri[j]);
System.out.println(tri[k]);
break lbl;
}
}
}
}
}
public int[] createTriangularNumbers(int n){
int[] out = new int[n+1];
for(int i=1,sum=0; i<=n;i++){
out[i] = sum += i;
}
return out;
}
As far as I can see, there is no direct formula. An algorithm is needed. For instance, a greedy method does not work. Take for example the value 90:
The greatest triangular number not greater than 90 is 78. Remains 12
The greatest triangular number not greater than 12 is 10. Remains 2
And now it becomes clear we will need 4 terms which is not acceptable.
So I would propose a recursive/backtracking algorithm, where each recursive call deals with one summand only. Each level in the recursion takes first the highest possible triangular number, but if the recursive call fails, it will go for the second largest and dive into recursion again, until there is an acceptable sum.
We can use the formula mentioned at maths.stackexchange.com:
Let Tm be the largest triangular number less than or equal to c.
You can actually get an explicit formula for m, namely:
Here is a snippet that implements the recursion. When running it, you can introduce a value, and the triangular summands will be produced for it.
function getTriangularTerms(n, maxTerms) {
if (maxTerms === 0 && n > 0) return null; // failure: too many terms
if (n == 0) return []; // Ok! Return empty array to which terms can be prepended
// Allow several attempts, each time with a
// lesser triangular summand:
for (let k = Math.floor((Math.sqrt(1+8*n) - 1) / 2); k >= 1; k--) {
let term = k * (k+1)/2;
// Use recursion
let result = getTriangularTerms(n - term, maxTerms - 1);
// If result is not null, we have a match
if (result) return [term, ...result]; // prepend term
}
}
// I/O handling
let input = document.querySelector("input");
let output = document.querySelector("span");
(input.oninput = function () { // event handler for any change in the input
let n = input.value;
let terms = getTriangularTerms(n, 3); // allow 3 terms max.
output.textContent = terms.join("+");
})(); // execute also at page load.
Enter number: <input type="number" value="14"><br>
Terms: <span></span>
Since a triangular number is any number t that satisfies t=x(x+1)/2 for any natural number x, what you're asking is to solve
n = a(a+1)/2 + b(b+1)/2 + c(c+1)/2
and to find the solution (a,b,c) with greatest possible max(a,b,c). You didn't specify that you only allow solutions with 3 triangular numbers, so I will assume you also allow solutions of the form (a,b,c,d) and look for the one with the greatest max(a,b,c,d).
There might be multiple solutions, but one with at most 3 triangular numbers always exists. Since it's possible to form any number with 3 triangular numbers, you can find the largest triangular number t with t<=n, and then it will follow n=t+d, where d=n-t. d is a natural number >=0 and therefore can be composed by 3 triangular numbers itself. Since you're interested in the largest summand, the largest will be t, which can be computed with t=x(x+1)/2 where x=floor((sqrt(1+8n)-1)/2) (obtained by solving the formula n=x(x+1)/2+d).
As a practical example, take n=218. With the formula, we get x=20 and t=210, which indeed is the largest triangular number before 218. The other triangular numbers, in this case, will be 6, 1, 1 since the only way to compute 8 is with those.

How can I loop through a Sudoku board?

For example, say we have a Sudoku board like this:
0 0 6 5 8 9 7 4 3
0 5 0 0 0 0 0 6 0
7 0 9 0 6 0 1 0 0
0 3 0 0 0 2 0 8 7
0 0 1 0 0 0 4 0 0
8 9 0 6 0 0 0 5 0
0 0 2 0 5 0 3 0 6
0 7 0 0 0 0 0 9 0
3 1 8 4 9 6 5 0 0
I want to store it into one array such that the first 9 elements of the array are the first sub block, i.e. the values {0 0 6 0 5 0 7 0 9} and followed by {5 8 9 0 0 0 0 6 0}.
I've tried finding a solution but I always get an array index out of bounds error and it is too brute force. Something similar to this:
while(st.hasMoreTokens()) {
if(ctr == 27) {
c.addSubBlock(sb1);
c.addSubBlock(sb2);
c.addSubBlock(sb3);
sb1 = new SubBlock();
sb2 = new SubBlock();
sb3 = new SubBlock();
ctr = 0;
}
sb1.addElement(Integer.parseInt(st.nextToken()));
sb1.addElement(Integer.parseInt(st.nextToken()));
sb1.addElement(Integer.parseInt(st.nextToken()));
sb2.addElement(Integer.parseInt(st.nextToken()));
sb2.addElement(Integer.parseInt(st.nextToken()));
sb2.addElement(Integer.parseInt(st.nextToken()));
sb3.addElement(Integer.parseInt(st.nextToken()));
sb3.addElement(Integer.parseInt(st.nextToken()));
sb3.addElement(Integer.parseInt(st.nextToken()));
ctr+=9;
}
Please give me some tips. Code snippets would also be a great help.
EDIT: This thread somehow helped me figured it out. And yes, this is part of the Sudoku where I'm trying to encode the board into an array.
What I did was to transform first the input String into a 2d array (9x9) and use int block = (row/3)*3 + (col/3); to compute exactly which sub block each element belongs.
Create a 3x3 array of sub blocks
Use 2 counters (x & y) for tracking the position in the full board of each element read
Add the values at (x,y) into sub block (x/3,y/3)
Something like this:
SubBlock board[][] = new SubBlock[3][3];
int x, y;
for ( y=0; y<9; y++ )
for ( x=0; x<9; x++ )
board[y/3][x/3].addElement(Integer.parseInt(st.nextToken()));
board[0][0] will be the top-left SubBlock, board[2][2] the bottom-right one.
Store everything in a two dimension array. E.g.
int[] board = {
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}
{1,2,3,4,5,6,7,8,9}};
//looping
public static void Main(string[] args){
for(int i = 0; i < 9; i++)
{
System.out.println("SubBlock number"+i);
for(int j = 0; j < 9; j++){
System.out.println(board[i][j]);
}
}
}
Assuming that you are reading input left to right, top to bottom, try a set of 4 nested loops like this:
int board[] = new int[81];
for (int outY = 0; outY < 3; outY++)
{
for (int outX = 0; outX < 3; outX++)
{
for (int inY = 0; inY < 3; inY++)
{
for (int inX = 0; inX < 3; inX++)
{
board[27*outY + 9*outX + 3 * inY + inX] = //parse an int from your input here
}
}
}
}
It would be great if we knew why you are trying to loop through the board.
If you want to check if you can enter a number, I recommend you use maps for each of the 3x3 squares.
Then check if the item is in the map already or not. For the rows and columns, you can either loop over the 2D array and check each element, or -again- use a map for each column and a map for each row.
I'm not entirely sure if you want an answer for a single-dimension array or if you're willing to make it a two-dimensional array (as you mention each nine element set with curly braces), but if two-dimensional is OK...
The OP in this Code Review posting used a 'fancy' way of sifting through the subgrids by using the math (i % 3) + rowStart inside one of the square brackets and (i / 3) + colStart inside the other. One commenter noted this modulo method to be a bit obscure, and I'm prone to agree, but for how clean it is and the fact that it works, I think it's a solid solution. So, paired with the iteration of the for loop, we can sift through each 'subgrid' cell, as well as each element of row + col.
for(i=0; i<9; ++i)
{
if (puzzle[row][i] == num) return 0;
if (puzzle[i][col] == num) return 0;
if (puzzle[rowStart + (i%3)][colStart + (i/3)] == num) return 0;
}
If we find a number in one of the cells that matches, it's a duplicate, and we exit the function as 'false', or, 0.
EDIT:
Now that I think of it, you could use this same trick for a single-dimension array by using i % 9 instead of 3. You could then determine which 'row' we're on by doing i / 9 and trusting that, since we're dealing with type ints, we'll truncate the unnecessary decimals.
This does verify that this trick is a bit prone towards N-1 indexed data, as someone would assume 'go to the 81st element' would mean go to the 9th column of the 9th row, but using 81 % 9 would yield 0, and 81 / 9 would yield 9, so we'd go to the 0th place at row 9.

How can I make this method end its recursion and reach a maximum?

I ran into a StackOverflowError when running a solution I wrote to an assignment.
These are the exact instructions from the book Java Methods: A & AB:
Write a program in which Cookie Monster finds the optimal path from the upper left corner (0,0) to the lower right corner(SIZE-1,SIZE-1) in a cookie grid (a 2-D array). The elements of the grid contain cookies (a non-negative number) or barrels (-1). On each step, Cookie Monster can only go down or to the right. He is not allowed to step on barrels. The optimal path contains the largest number of cookies.
The program reads the cookie grid from a file and reports the number of cookies on the optimal path. (The path itself is not reported.) A sample data file is provided in JM\Ch19\Exercises\cookies.dat.
Hint: Use a stack. If there is only one way to proceed from the current position, then go there and update the total accumulated number of cookies. If there are two ways to proceed, save one of the possible two points (and its total) on the stack and proceed to the other point. If you have reached the lower-right corner, update the maximum. If there is nowhere to go, examine the stack: pop a saved point, if any, and resume from there.
The goal is to give my teacher the best possible path (the one with the most "cookies" on it).
Okay. so the mentioned cookie map file is this:
1 3 0 5 -1 7 -1 -1 0 4 2 1
-1 3 2 1 -1 4 -1 5 3 -1 1 0
5 4 8 -1 3 2 2 -1 4 -1 0 0
2 1 0 4 1 -1 8 0 2 -1 2 5
1 4 0 1 -1 0 3 2 2 4 1 4
0 1 4 1 1 6 1 4 5 2 1 0
3 2 5 2 0 7 -1 2 1 0 -1 3
0 -1 4 -1 -1 3 5 1 4 2 1 2
5 4 8 -1 3 2 2 -1 4 -1 0 0
2 1 0 4 1 -1 8 0 2 -1 2 5
1 3 0 5 -1 7 -1 -1 0 4 2 1
0 0 3 1 5 2 1 5 4 1 3 3
And this is the class I use to get a 2-D array of the numbers (I know this part works.) Using A BlueJ debugger, the 2-D array seems to be what I want it to be.
import java.util.*;
import java.io.*;
public class MapReader
{
public static int[][] grid;
public static Scanner gridscanner = null;
public static int[][] getMap()
{
File file = new File("cookies.dat");
try
{
gridscanner = new Scanner(file);
}
catch (FileNotFoundException ex)
{
System.out.println("*** Cannot open cookis.dat ***");
System.exit(1);
}
int row = 12;
grid = new int[row][row];
for(int r = 0; r < row; r++)
{
for(int c = 0; c < row; c++)
{
grid[r][c] = gridscanner.nextInt();
}
}
return grid;
}
}
And here is a class I use to keep track of saved positions, their values, and their locations for when I'm traversing this "cookie map":
import java.util.*;
public class Point
{
int row;
int col;
int total;
public Point(int r, int c, int t)
{
row = r;
col = c;
total = t;
}
public int getRow() { return row; }
public int getCol() { return col; }
public int getValue() { return MapReader.getMap()[row][col]; }
public int getTotal() { return total; }
}
And finally, here is the class that I use to recursively travel through the 2D array. You'll notice that I prefer to go right when two paths are available but then go down when I pop a Point from the "saved" Stack. The problem lies in this class as far as I know: How can I make the method end its recursion and reach a maximum?
import java.util.*;
public class CookieMonster
{
private static int[][] map = MapReader.getMap();
private static int max = 11;
private static int total, maximum;
private static Stack<Point> saved = new Stack<Point>();
public static void main(String[] args)
{
System.out.println(move(0,0));
}
public static int move(int r, int c)
{
int right = 0;
int down = 0;
boolean isright = true;
boolean isdown = true;
if (c < max)
{
right = map[r][c + 1];
}
else
isright = false;
if (r < max)
{
down = map[r + 1][c];
}
else
isdown = false;
if (right == -1)
isright = false;
if (down == -1)
isdown = false;
if (isright && isdown)
{
saved.push(new Point(r + 1, c, total + down));
total += right;
move(r, c + 1);
}
else if (isright)
{
total += right;
move(r, c + 1);
}
else if (isdown)
{
total += down;
move(r + 1, c);
}
else
{
if (r == max && c == max)
{
if (maximum < total)
maximum = total;
}
if (!saved.isEmpty())
{
Point sd = saved.pop();
total = sd.getTotal();
move(sd.getRow(), sd.getCol());
}
}
return maximum;
}
}
I know the hint suggests to use a stack, but this problem can be solved much more efficiently using dynamic programming. It is basically recursion with a memory of previously visited paths to avoid recomputation.
Assuming you index the matrix starting at 1, Your cost function should be as follows:
c(i, j) = -INF if i == 0 or j == 0 or data(i, j) < 0
data(1, 1) if i == 1 and j == 1
data(i, j) + min(c(i, j - 1), c(i - 1, j))
You can iterate in the usual nested i-j loop from left to right and up to down.
c(n, n) will give you the result of the optimal path.
This seems np-complete. Using a stack and writing the logic to return to a former path if you run into a dead-end seems like wasted effort. You are going to have to use a lot of brute force even with the stack and logic. It seems easier to just use a primitive to store the number of cookies and just write some logic to move down and right at random. If you hit a dead end, just throw that result out and start over. If you hit the end, save that value and check to see if it is larger than a previous path. It if it is, keep it until you find a larger one. If you run it enough times, you will find the best path. I can't imagine it would take more than a few seconds to find the most cookies.

Categories

Resources