I have a question about my homework in scratching my head-on.
So I need to build a program that counts the number of areas of true value (near to each other) in the 2D array.
{0,1,0,0}
{1,0,0,1}
{1,1,0,1}
{1,0,0,1}
So the program needs to return 3 because there 3 places with trues.
If there are no true then to return 0.
The program needs to recursive and without loops.
Thanks in advance to the ones that will help me solve this one. I didn't even have any idea how to start it.
Ok, you do a dfs to record the cells you went and you can have a boolean[][] to record the cells you went. Then you just loop through the grid to see where you have not gone. If you did not go there yet, go there and also perform a dfs on nearby cells, but anyway, a code would be more clear.
public static int[][] grid;
public static boolean[][] went;
public static int r, c;
public static void dfs(int x, int y) {
if (x < 0 || x >= r || y < 0 || y >= c) {//out of the grid
return;
}
if (went[x][y]) {//I went here
return;
}
went[x][y] = true;
if (grid[x][y] == 0) {//It's false here so don't go
return;
}
dfs(x - 1, y);
dfs(x + 1, y);
dfs(x, y - 1);
dfs(x, y + 1);
}
public static void main(String[] args) throws IOException {
BufferedReader input =
new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(input.readLine());
//input reading
r = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
grid = new int[r][c];
went = new boolean[r][c];
for (int i = 0; i < r; i++) {
st = new StringTokenizer(input.readLine());
for (int j = 0; j < c; j++) {
grid[i][j] = Integer.parseInt(st.nextToken());
}
}
//end of input reading
int cnt = 0;//number of areas
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
// If I have not went have and the value
// must be true so I would perform a dfs
// (since I only care about the value of 1s)
if (!went[i][j] && grid[i][j] == 1) {
cnt++;//add to our counter
dfs(i, j);//have not went here
}
}
}
System.out.println(cnt);
}
This solution uses the only recursion. No loops.
public static void main(String... args) {
System.out.println(countTrueAreas(new int[][] {
{ 0, 1, 0, 0 },
{ 1, 0, 0, 1 },
{ 1, 1, 0, 1 },
{ 1, 0, 0, 1 } })); // 3
}
public static int countTrueAreas(int[][] grid) {
return countTrueAreas(grid, 0, 0, 10) - 10;
}
private static int countTrueAreas(int[][] grid, int row, int col, int num) {
if (row == grid.length)
return num;
if (col == grid[row].length) {
if (++row == grid.length)
return num;
col = 0;
}
if (grid[row][col] == 1)
dfs(grid, row, col, num++);
return countTrueAreas(grid, row, col + 1, num);
}
private static void dfs(int[][] grid, int row, int col, int num) {
if (row < 0 || row >= grid.length)
return;
if (col < 0 || col >= grid[row].length)
return;
if (grid[row][col] != 1)
return;
grid[row][col] = num;
dfs(grid, row, col - 1, num);
dfs(grid, row, col + 1, num);
dfs(grid, row - 1, col, num);
dfs(grid, row + 1, col, num);
}
Related
I am working on a Percolation java program. I have implemented the following Percolation.java file and am running into an error when testing it with certain input files, as described below.
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
public class Percolation {
private int n;
private WeightedQuickUnionUF verify;
private WeightedQuickUnionUF solution;
private int sink;
private int source = 0;
private boolean[][] grid;
private int openSites = 0;
private int length;
// creates n-by-n grid, with all sites initially blocked
public Percolation(int n) {
if (n <= 0) {
throw new IllegalArgumentException();
}
this.length = n;
this.grid = new boolean[length][length];
this.sink = (length * length) + 1;
verify = new WeightedQuickUnionUF(length * length + 2);
solution = new WeightedQuickUnionUF(length * length + 2);
for (int i = 0; i < length; i++) {
verify.union(encode(0, i), source);
solution.union(encode(0, i), source);
}
for (int j = 0; j < length; j++) {
verify.union(encode(n - 1, j), sink);
}
}
// opens the site (row, col) if it is not open already
public void open(int row, int col) {
grid[row][col] = true;
openSites++;
if ((row - 1) >= 0 && isOpen(row - 1, col)) {
verify.union(encode(row, col), encode(row - 1, col));
solution.union(encode(row, col), encode(row - 1, col));
}
if ((row + 1) < length && isOpen(row + 1, col)) {
verify.union(encode(row, col), encode(row + 1, col));
solution.union(encode(row, col), encode(row + 1, col));
}
if ((col - 1) >= 0 && isOpen(row, col - 1)) {
verify.union(encode(row, col), encode(row, col - 1));
solution.union(encode(row, col), encode(row, col - 1));
}
if ((col + 1) < length && isOpen(row, col + 1)) {
verify.union(encode(row, col), encode(row, col + 1));
solution.union(encode(row, col), encode(row, col + 1));
}
}
// is the site (row, col) open?
public boolean isOpen(int row, int col) {
return grid[row][col];
}
// is the site (row, col) full?
public boolean isFull(int row, int col) {
return solution.find(source) == solution.find(encode(row, col));
}
// returns the number of open sites
public int numberOfOpenSites() {
return openSites;
}
// does the system percolate?
public boolean percolates() {
return verify.find(0) == verify.find(sink);
}
// An integer ID (1...n) for site (i, j).
private int encode(int row, int col) {
int number = length * row + 1 + col;
return number;
}
// unit testing (required)
public static void main(String[] args) {
String filename = args[0];
In in = new In(filename);
int n = in.readInt();
Percolation perc = new Percolation(n);
while (!in.isEmpty()) {
int i = in.readInt();
int j = in.readInt();
perc.open(i, j);
}
StdOut.println(perc.numberOfOpenSites() + " open sites");
if (perc.percolates()) {
StdOut.println("percolates");
}
else {
StdOut.println("does not percolate");
}
// Check if site (i, j) optionally specified on the command line
// is full.
if (args.length == 3) {
int i = Integer.parseInt(args[1]);
int j = Integer.parseInt(args[2]);
StdOut.println(perc.isFull(i, j));
}
}
}
However, when I test the code using certain input files, I receive error messages such as the following:
java.lang.ArrayIndexOutOfBoundsException: Index 8 out of bounds for length 8
Percolation.isOpen(Percolation.java:63)
TestPercolation.checkIsOpen(TestPercolation.java:122)
TestPercolation.checkIsOpen(TestPercolation.java:105)
TestPercolation.check(TestPercolation.java:177)
TestPercolation.checkFile(TestPercolation.java:198)
TestPercolation.test1(TestPercolation.java:659)
TestPercolation.main(TestPercolation.java:963)
java.lang.ArrayIndexOutOfBoundsException: Index 25 out of bounds for length 25
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
What in my code could be causing this? In other words, where is the issue and how can I fix it?
This is all about the famous NQueens problem. My program works fine (backtrack approach). It finds all the solutions for a given board size.
Code is shown below.
I'm trying to modify the code so that I can find all the solutions for a given column of the first queen. I don't want to change the position of first queen. For an example it will provide me with the solution of
[2, 0, 3, 1, 4] and [2, 4, 1, 3, 0]
when I set the first queen at 2, board size 5 (third column, index starts from zero).
I tried this by setting different values for k (and board[k] as well) but doesn't quite reach the goal.
Any hints will be appreciated.
Here is my code. Removed details about place method since it shouldn't be changed to achieve my new goal.
public class NQueensAllSolutions
{
// Board size
static int size = 8;
// One dimensional array to store the column number for all queens.
static int[] board = new int[size];
// This method will check the validity for a new queen. works fine.
static boolean place(int k)
{
.
.
}
public static void main(String[] args)
{
int k;
long t=0; // for counting total found solutions
k = 0;
board[k] = -1;
while(k >= 0) {
board[k]++;
while(board[k] < size && !(place(k))) board[k]++;
if(board[k] < size) {
if(k == size-1) { // a solution is found.
t++;
//System.out.println("\n\nTotal: "+t+" --> "+Arrays.toString(board));
}
else {
k++; board[k] = -1;
}
}
else {
k--; // backtrack.
}
}
System.out.println("\n\nTotal: "+t);
}
}
Just keep k greater than 0 in the while loop:
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
public static void main(String[] args)
{
int t = 0;
// Set the first queen position
board[0] = 2;
int k = 1;
board[k] = -1;
// k must stay greater than 0
while(k >= 1) {
board[k]++;
while(board[k] < size && !isValid(k))
board[k]++;
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [2, 0, 3, 1, 4]
Solution 2 --> [2, 4, 1, 3, 0]
UPDATE
Here is a generalized version that can force a queen at position (fixedRow, fixedCol).
The key change is the new getNextCol() method, which is used to get the next possible column for a queen. On row fixedRow, the only possible column is fixedCol. On the other rows, all columns are possible.
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int fixedRow = 2;
static int fixedCol = 0;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
static int getNextCol(int k, int col)
{
if(k == fixedRow) {
// Only one possible move on this row
return col == -1 ? fixedCol : size;
}
else {
// Try the next column
return col+1;
}
}
public static void main(String[] args)
{
int t = 0;
int k = 0;
board[k] = -1;
while(k >= 0) {
board[k] = getNextCol(k, board[k]);
while(board[k] < size && !isValid(k))
board[k] = getNextCol(k, board[k]);
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [1, 3, 0, 2, 4]
Solution 2 --> [4, 2, 0, 3, 1]
Here is the method, it ideally should solve the eight-queens problem by placing Qs on the board so that none of them threaten each other, but I can't seem to stop it from infinitely recursing.
public static void solve(int row, int col, int size, char[][] array) {
for (int i = 0; i < size - 2; i++) {
if (isSafe(row, col, size, array)) {
array[i][col] = 'Q';
} else {
if (col < size - 2) {
solve(row, col++, size, array); //changed ++ to +1
}
}
}
}
For clarity, here is the included 'isSafe' method:
public static boolean isSafe(int row, int col, int size, char[][] array) {
//check column
for (int i = 0; i < size - 1; i++) {
if (array[i][col] == 'Q') {
return false;
}
}
//horizontal
for (int i = size - 1; i >= 0; i--) {
if (array[row][i] == 'Q') {
return false;
}
}
//up diagonal
while (row > 0 && col > 0) {
int x = row;
int y = col;
if (array[row - 1][col - 1] == 'Q') {
return false;
} else {
x--;
y--;
}
}
//down diagonal
while (row < size - 1 && col > 0) {
int x = row;
int y = col;
if (array[row + 1][col - 1] == 'Q') {
return false;
} else {
x++;
y--;
}
}
return true;
}
Thank you for any light you can shed on this.
EDIT : So I just figured out that by changing '++' to '+1' I was able to stop the stack overflow, but my method does not recurse like I want it to so a question still remains
The problem is with solve(row, col++, size, array);
col will not be incremented until AFTER the call to solve.
You need to use solve(row, ++col, size, array);
I'm trying to create a strategy that will play against human or another strategy for the game Gomoku. I already have some kind of minimax function, although i don't quite understand how does it work and i also have a getscore function, which should send back the best score to minimax ? But the problem is that my getScore function does not recognize if there are 4 or 5 circles in a row/col/diagonally.
Here is my code:
public class JarmoStrategyV1 implements ComputerStrategy {
public static int Lrow = 0;
public static int Lcol = 0;
public static int Drow = 0;
public static int Dcol = 0;
public static final int E = 0;
public static final int X = 1; // black
public static final int O = -1; // white
public static final int WINSCORE = 100;
private static final int WINCOUNT = 5;
public Location getMove(SimpleBoard board, int player) {
// let's operate on 2-d array
int[][] b = board.getBoard();
System.out.println(getScore(b, player));
for (int row = 0; row < b.length; row++) {
for (int col = 0; col < b[0].length; col++) {
if (b[row][col] == SimpleBoard.EMPTY) {
// first empty location
return new Location(row, col);
}
}
}
return null;
}
#Override
public String getName() {
return "Student name";
}
public static int minimax(int[][] board, int player, int depth) {
if (getScore(board, player) == WINSCORE) {
//
return WINSCORE;
}
if (depth == 2) {
return getScore(board, player);
}
int max = Integer.MIN_VALUE;
if (player == -1){
max = Integer.MAX_VALUE;
}
System.out.println(max);
List<Location> possibleMoves = getPossibleMoves(board);
for (Location loc : possibleMoves) {
board[loc.getRow()][loc.getColumn()] = player;
int newplayer = 0 - player;
if(newplayer == 1){
int value = minimax(board, newplayer,depth + 1);
if(value < max) {
max = value;
}
}
if (newplayer == -1){
int value = minimax(board, newplayer, depth + 1);
if (value > max) {
max = value;
}
}
board[loc.getRow()][loc.getColumn()] = E;
}
return max;
}
public static int getScore(int[][] board, int muutuja) {
//int yks = 0;
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
if (board[row][col] == muutuja) {
if (row <= (board.length - 5)) {
if (col <= board.length && getCount(board, row, col, 0, 1, muutuja, WINCOUNT) >= (WINCOUNT - 1) && getCount(board, row, (col + 4), 0, 1, E, 1 ) >= 1) return 1; // - 4 in a row
if (row >= 1 && getCount(board, row, col, 1, 0, muutuja, WINCOUNT) >= (WINCOUNT -1) && getCount(board, (row - 1), col, 1, 0, E, 1) == 1) return 1;
if (getCount(board, row, col, 1, 0, muutuja, WINCOUNT) >= WINCOUNT) return 100; // | 5 in a row
if (col <= WINCOUNT && getCount(board, row, col, 1, 1, muutuja, WINCOUNT) >= WINCOUNT) return 100; // \
if (col >= WINCOUNT && getCount(board, row, col, 1, -1, muutuja, WINCOUNT) >= WINCOUNT) return 100; // /
}
if (col <= WINCOUNT && getCount(board, row, col, 0, 1, muutuja, WINCOUNT) >= WINCOUNT) return 100; // -
}
}
}
return 0;
}
public static int getCount(int[][] board, int row, int col, int rowd, int cold, int player, int test) {
int count = 0;
for (int i = 0; i < test; i++) {
if (board[row + i * rowd][col + i * cold] == player) count++;
else break;
}
return count;
}
public static ArrayList<Location> getPossibleMoves(int[][] board) {
ArrayList<Location> availableMoves = new ArrayList<Location>();
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
if (board[row][col] == E) {
availableMoves.add(new Location(row, col));
}
}
}
return availableMoves;
}
}
There seems to be some kind of a problem with getScore, when i run this code then i can only play for a while until my Gomoku app crashes.
If you want to try this out yourself then you can open this via Eclipse.
Download the project file: http://www68.zippyshare.com/v/feWl2QwC/file.html
Import it to eclipse projects/workspace.
And you also have to build path to those 2 jar files in lib folder.
NOTE: I can only edit files in gomoku.strategies package.
the stacktrace shows an exception. add debug print or run with debugger
java.lang.IllegalArgumentException: It's computer's turn, pass the player to makeMove()
at gomoku.Game.makeMove(Game.java:476)
I'm trying to write a backtracking code that will find the number of solutions in a NQueens problem. But I am getting stack overflows when I try to mark the diagonal grids where it is not safe to place a queen.
int dim;
private void recurseMark(int row, int col, boolean[][] board, boolean val) {
if(row >= dim || col >= dim || row < 0 || col < 0) return;
if(board[row][col]) return;
System.out.println("Row " + row + " Col " + col);
board[row][col] = val;
recurseMark(row+1, col-1, board, val);
recurseMark(row+1, col+1, board, val);
recurseMark(row-1, col+1, board, val);
recurseMark(row-1, col-1, board, val);
}
private void mark(int i, int k, boolean[][] board, boolean val) {
for(int j = 0; j < dim; j++) {
board[i][j] = val;
}
for(int j = 0; j < dim; j++) {
board[j][k] = val;
}
}
private int countQueens(int i, boolean[][] board) {
int count = 0;
if(i == dim) return 1;
for(int k = 0; k < dim; k++) {
if(!board[i][k]) {
board[i][k] = true;
mark(i, k, board, true);
System.out.println("Giving " + i + " " + k);
recurseMark(i, k, board, true);
count += countQueens(i+1, board);
recurseMark(i, k, board, false);
mark(i, k, board, false);
}
}
return count;
}
public int totalNQueens(int n) {
dim = n;
boolean[][] board = new boolean[n][n];
return countQueens(0, board);
}
public static void main(String[] args) {
NQueens nq = new NQueens();
System.out.println(nq.totalNQueens(2));
}
Any idea why it's overflowing for a small value of N?
Because your method recurses infinitely.
If the board is 8x8, then for example recurseMark(1, 1, board, false) calls recurseMark(2, 2, board, false) which calls recurseMark(1, 1, board, false) which calls recurseMark(2, 2, board, false) which calls recurseMark(1, 1, board, false) which ...
The problem is when recurseMark is called with false. Here is a correct recurseMark():
private void recurseMark(int row, int col, Boolean[][] board, Boolean val) {
if(row >= dim || col >= dim || row < 0 || col < 0) return;
if(board[row][col] != null) return;
System.out.println("Row " + row + " Col " + col);
board[row][col] = val;
recurseMark(row+1, col-1, board, val);
recurseMark(row+1, col+1, board, val);
recurseMark(row-1, col+1, board, val);
recurseMark(row-1, col-1, board, val);
}
What we have done here is to switch to a Boolean class rather than primitive boolean, and use the null case to represent "square not visited yet". As it was the "square not visited" state was "false".