Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
UPDATED CODE: My last question is how do I get it so that my program prints all 92 solutions of an 8x8 board, without any Queens attacking each other? So far, my code only prints 1 solution. For example, when I change it to a 4x4 board, I only have 1 solution, when there should be 2 I believe.
public class Queen{
public static void display(int[] board){
int n = board.length;
for(int column = 0; column < n; column++){
for(int row = 0; row < n; row++){
if(board[column] == row)
System.out.print('Q');
else
System.out.print('x');
}
System.out.print('\n');
}
}
public static int[] solveQueens(int n){
int board[] = new int[n];
placeQueen(board,0);
return board;
}
private static boolean placeQueen(int[] board, int column){
int n = board.length;
if (n == column){
return true;
}else{
for (int row = 0; row < n; row++){
int i; //remove
for (i = 0; i < column; i++){ //for (int i)
if (board[i] == row || i - column == board[i] - row || column - i == board[i] - row){
break;
}
}
if (i == column){
board[column] = row;
if (placeQueen(board, column + 1))
return true;
}
}
}
return false;
}
public static void main(String args[]){
int finished[] = solveQueens(8);
display(finished);
}
}
Now my programs returns:
Qxxxxxxx
xxxxQxxx
xxxxxxxQ
xxxxxQxx
xxQxxxxx
xxxxxxQx
xQxxxxxx
xxxQxxxx
OLD CODE:
I need to use recursive backtracking to solve the 8-queens problem. The n-queens problem is a puzzle that requires placing n chess queens on an n × n board so that none of the queens attack each other.
I need to Write a public solveQueens(int n) method to solve the problem for an nxn board
I also need to write a private recursive placeQueen(board, column) method to attempt to place a queen in the specified column.
This is my code so far:
public class Queen{
public static int[] solveQueens(int n){
int board[] = new int[n];
int finished[] = placeQueen(board,0);
return finished;
}
private static int[] placeQueen(int[] board, int column){
int n = board.length;
int row = column;
if (n == column){
return board;
}else{
for (row = n; row < n; row++){
board[column] = row;
if (board[n] == 0 && board[n-1] == 0 && board[n+1] == 0){
board[n] = 1;
placeQueen(board, column+1);
}
}
for (row = n; row < n; row++){
board[row] = column;
if (board[n] == 0 && board[n-1] == 0 && board[n+1] == 0){
board[n] = 1;
placeQueen(board, column+1);
}
}
}
return board;
}
public static void main(String args[]){
int finished[] = solveQueens(8);
for (int item: finished){
System.out.print(item);
}
}
}
Whenever I run my program, all it returns is
----jGRASP exec: java Queen
00000000
Is there any explanation on how to setup my 8x8 board, and how to place queens so they don't attack each other?
I made some changes in solveQueens and placeQueen:
public class Queen{
public static int[] solveQueens(int n){
int board[] = new int[n];
placeQueen(board,0); //it fills the board
return board;
}
private static boolean placeQueen(int[] board, int column){
int n = board.length;
int row;
if (n == column){
return true;
}else{
for (row = 0; row < n; row++){
int c;
for (c=0; c<column; c++){
if (board[c]==row || c-column==board[c]-row || column-c==board[c]-row){
//check if it is safe position (we know 2 queens couldn't place in a same column or row or diameter
break;
}
}
if (c==column){ //if previous loop didn't break...=> it is safe position
board[column]=row;
if (placeQueen(board, column+1)) //if it is possible to fill the rest of board //else: test the next row
return true;
}
}
}
return false;
}
public static void main(String args[]){
int finished[] = solveQueens(8);
for (int item: finished){
System.out.print(item);
}
}
}
Related
I am trying to write a DFS code for finding the clusters of size greater than or equal to 2 inside a 2D matrix of integers. I am trying to write the DFS for that. Here I am unable to get any output inside the win cluster list of Cluster Object. Can anybody suggest what is going wrong. I have written a DFS function that calls for all neighbouring locations(horizontally and vertically).
Also checking for the valid condition for checking whether the indices are inside the row and column constraints. When the DFS is terminating I am checking for the condition if count of cluster is greater than 2 then I'll add it to the win clusters list else simply return.Please suggest why am I not getting any value in the win_clusters list.
import java.util.*;
public class sample {
static int grid[][]= {{1,3,0,4,0},
{3,2,0,0,1},
{0,4,1,0,1},
{4,0,0,0,2},
{2,4,0,2,4}};
static int ROW;
static int COLUMN;
public static int[][] grid_creation(int numRows, int numCols){
ROW= numRows;
COLUMN=numCols;
int [][]grid = new int[numRows][numCols];
Random rand = new Random();
for(int i = 0; i<numRows ; i++){
for(int j = 0; j<numCols; j++){
grid[i][j]= rand.nextInt(5);
}
}
return grid;
}
public static void print_matrix(int[][]matrix){
for(int i = 0; i< matrix.length;i++){
for(int j = 0; j<matrix[0].length; j++){
System.out.print(matrix[i][j]+" ");
}
System.out.println();
}
}
public static boolean isValid(boolean[][] visited, int row, int col){
if(row<0 ||col<0 || row>=ROW || col>=COLUMN || visited[row][col] )
return false;
return true;
}
public static class Cluster{
List<Integer> cluster_symbol_positions = new ArrayList<Integer>();
int symbol = -1;
int count = 0;
int win = 0;
public void create_new_Cluster(){
cluster_symbol_positions = new ArrayList<>();
symbol = -1;
count = 0;
win= 0;
}
public List<Integer> get_cluster_symbol_positions(){
return cluster_symbol_positions;
}
public int getSymbol(){return symbol;}
public void setSymbol(int a){symbol = a;}
public int getCount(){return count;}
public void add_to_cluster(int row1, int col1 ){
int row = row1;
int col = col1;
cluster_symbol_positions.add(getReelPositionNumber(row,col));
count++;
}
public int cluster_win(Cluster cluster){
int win_amount = 0;
//return win amount from the paytable
return win_amount;
}
}
public static void DFS(int[][] grid,List<Cluster> win_clusters) {
int h = grid.length;
if (h == 0)
return;
int l = grid[0].length;
//created visited array
boolean [][] visited = new boolean[h][l];
System.out.println("Depth-First Search: ");
for( int i =0; i< ROW ; i++){
for(int j = 0 ;j<COLUMN; j++){
if(!visited[i][j]) {
DFSUtil(grid, i, j, visited, win_clusters);
}
}
}
}
static Cluster global_cluster= new Cluster();
static int cluster_length =0;
public static void DFSUtil(int[][]grid, int row, int col, boolean[][] visited, List<Cluster>win_clusters){
if (row < 0 || col < 0 || row >= ROW|| col >= COLUMN || visited[row][col] ) {
if(global_cluster.getCount()>=2) win_clusters.add(global_cluster);
return;
}
int symbol = grid[row][col];
visited[row][col] = true;
cluster_length++;
global_cluster.add_to_cluster(row,col);
global_cluster.setSymbol(symbol);
if(isValid(visited, row+1, col) && grid[row+1][col]==symbol){
DFSUtil(grid, row+ 1, col,visited,win_clusters); // go down
}
if(isValid(visited, row-1, col) && grid[row-1][col]==symbol) {
DFSUtil(grid, row - 1, col, visited, win_clusters); //go up
}
if(isValid(visited, row, col+1) && grid[row][col+1]==symbol){
DFSUtil(grid, row, col + 1,visited,win_clusters); //go right
}
if(isValid(visited, row, col-1) && grid[row][col-1]==symbol){
DFSUtil(grid, row, col - 1,visited,win_clusters); // go left
}
}
public static int getReelPositionNumber(int row, int col) {
return (row*COLUMN) + col;
}
public static List<Integer> getReelPositionsIndex(int positionNumber) {
List<Integer> tempData = new ArrayList<Integer>();
int numReels =COLUMN;
int display = ROW;
if(positionNumber >= numReels*display)
throw new RuntimeException( positionNumber+" is out of range "+ numReels*display +"(rows*cols) in the game." );
if(positionNumber < numReels) {
tempData.add(0);
tempData.add(positionNumber);
} else if(positionNumber == (numReels*display)) {
tempData.add(display - 1);
tempData.add(numReels - 1);
} else {
int row = positionNumber / numReels;
int col = positionNumber % numReels;
tempData.add(row);
tempData.add(col);
}
return tempData;
}
public static void main(String args[]){
System.out.println("Modified function for cluster win ");
List<Cluster> win_clusters = new ArrayList<Cluster>();
DFS(grid,win_clusters);
print_matrix(grid);
System.out.println(win_clusters.size());
}
}
I have the working code that you can see bellow, I just need someone to help me how to enable user to insert number of queens in a new window and then the program should show all solutions in a new window that will graphically show the chessboard and the queens.
Java program to solve N Queen
Problem using backtracking
public class GfG
{
static int N = 2;
static int k = 1;
/* A utility function to print solution */
static void printSolution(int board[][])
{
System.out.printf("%d-\n", k++);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
System.out.printf(" %d ", board[i][j]);
System.out.printf("\n");
}
System.out.printf("\n");
}
A utility function to check if a queen can
be placed on board[row][col]. Note that this
function is called when "col" queens are
already placed in columns from 0 to col -1.
So we need to check only left side for
attacking queens
static boolean isSafe(int board[][], int row, int col)
{
int i, j;
/* Check this row on left side */
for (i = 0; i < col; i++)
if (board[row][i] == 1)
return false;
/* Check upper diagonal on left side */
for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
if (board[i][j] == 1)
return false;
/* Check lower diagonal on left side */
for (i = row, j = col; j >= 0 && i < N; i++, j--)
if (board[i][j] == 1)
return false;
return true;
}
A recursive utility function
to solve N Queen problem
static boolean solveNQUtil(int board[][], int col)
{
/* base case: If all queens are placed
then return true */
if (col == N)
{
printSolution(board);
return true;
}
/* Consider this column and try placing
this queen in all rows one by one */
boolean res = false;
for (int i = 0; i < N; i++)
{
/* Check if queen can be placed on
board[i][col] */
if ( isSafe(board, i, col) )
{
/* Place this queen in board[i][col] */
board[i][col] = 1;
// Make result true if any placement
// is possible
res = solveNQUtil(board, col + 1) || res;
/* If placing queen in board[i][col]
doesn't lead to a solution, then
remove queen from board[i][col] */
board[i][col] = 0; // BACKTRACK
}
}
/* If queen can not be place in any row in
this column col then return false */
return res;
}
This function solves the N Queen problem using
Backtracking. It mainly uses solveNQUtil() to
solve the problem. It returns false if queens
cannot be placed, otherwise return true and
prints placement of queens in the form of 1s.
Please note that there may be more than one
solutions, this function prints one of the
feasible solutions.
static void solveNQ()
{
int board[][] = new int[N][N];
if (solveNQUtil(board, 0) == false)
{
System.out.printf("Solution does not exist");
return ;
}
return ;
}
// Driver code
public static void main(String[] args)
{
solveNQ();
}
}
I am currently trying to learn the topic of Backtracking in Java. It is really really confusing for me because I am stuck.
The problem is to find ways in which N Queens can be placed in NxN Chess board so that none of the Queens can attack each other. A queen can attack in the same row, same column and diagonally. My code goes like this:
import java.util.Scanner;
class Main {
public static void putZero(int[][] board,int n){
for(int i = 0;i<n;i++){
for(int j=0;j<n;j++){
board[i][j]=0;
}
}
}
public static void printBoard(int[][] board,int n){
for(int i = 0;i<n;i++){
for(int j=0;j<n;j++){
System.out.print(board[i][j]);
}
System.out.print("\n");
}
System.out.print("\n\n\n");
}
public static void SolveNQ(int n){
int[][] board = new int[n][n];
putZero(board,n);
if(SolveQUtil(board,0,n)==true){
printBoard(board,n);
}
}
public static boolean isSafe(int row, int col, int[][] board,int n){
int i,j;
for(i=0;i<col;i++){
if(board[row][i]==1)
return false;
}
for(i=row,j = col; i >= 0 && j >= 0; i--, j--){
if(board[i][j]==1)
return false;
}
for (i = row, j = col; j >= 0 && i < n; i++, j--)
if (board[i][j] == 1)
return false;
return true;
}
public static boolean SolveQUtil(int[][] board, int col, int n){
if(col>=n){
return true;
}
else
for(int i=0;i<n;i++){
if(isSafe(i,col,board,n)==true){
board[i][col]=1;
boolean a = SolveQUtil(board,col+1,n);
if(a==true)
return true;
else
board[i][col]=0;
}
}
return false;
}
public static void main(String[] args){
Scanner scan = new Scanner(`enter code here`System.in);
int n = scan.nextInt();;
SolveNQ(n);
}
}
It is producing the result I want, but I am not understanding how this works. In my method SolveQUtil(), the method is called again which is "recursive". When col = 0 is called, the Q1 is placed at [0,0] as there are no existing queens. But when col = 1 is called recursively, it searches for the suitable place and returns 'true'. Now, isn't the SolveNQ() supposed to print the solution every time true is returned? When does it return false? How is this working? I am a beginner and can anyone please explain this to me, step by step? Thank you in advance.
SolveNQ, which does the printing, is not called recursively; SolveQUtil, which SolveNQ calls, and which does not print anything, is recursive.
A friend gave me a class that tries to solve sudoku puzzels. Thing is the changes of the array inside the method is not reflected in the original array. Here's the code:
public static void solve(int array[][], int row, int col)
{
if( row > 8 )
{
printBoard(array); // this gives the correct result
return;
}
if( array[row][col] != 0 )
nextEmptyCell(array, row, col );
else
{
for( int num = 1; num < 10; num++ )
{
if(validityRowColBox(array, row, col, num))
{
array[row][col] = num;
nextEmptyCell(array, row, col);
}
}
array[row][col] = 0;
}
}
public static void nextEmptyCell(int array[][], int row, int col)
{
if( col < 8 )
solve(array, row, col + 1 );
else
solve(array, row + 1, 0 );
}
//This boolean methods will checks the validity of the number for the given row, columns and its designated box.
public static boolean validityRowColBox(int array[][], int row, int col, int num)
{
for(int c = 0; c <9; c++ )
{
if( array[row][c] == num )
return false;// It return false if the number is already exist in the given row.
}
for(int r = 0; r <9; r++ )
{
if(array[r][col] == num )
return false;// It return false if the number is already exist in the given columns.
}
row = (row / 3) * 3 ;
col = (col / 3) * 3 ;
for( int r = 0; r < 3; r++ )
{
for( int c = 0; c < 3; c++ )
{
if( array[row+r][col+c] == num )
return false;// It return false if the number is already exist in the designated box.
}
}
return true;// Otherwise true.
}
// sample input
public static int[][] easy ()
{
return new int[][]
{{0,0,0,2,6,0,7,0,1},
{6,8,0,0,7,0,0,9,0},
{1,9,0,0,0,4,5,0,0},
{8,2,0,1,0,0,0,4,0},
{0,0,4,6,0,2,9,0,0},
{0,5,0,0,0,3,0,2,8},
{0,0,9,3,0,0,0,7,4},
{0,4,0,0,5,0,0,3,6},
{7,0,3,0,1,8,0,0,0}};
}
public static void main(String args[])
{
int inputArray[][] = easy();
solve(inputArray,0,0);
printBoard(inputArray); // items still the same!
}
}
If I call the printBoard(array); function inside the method, the elements of the array appears to change. But when I call the printBoard(array); method in the main method on the original array, the changes are lost, the values are back to original again. I am extremely confused by this. None of the methods creates a new object so it should still point to the inputArray object. What's happening?
Edit: Here's the printBoard() method
public static void printBoard(int array[][])
{
//This is the board method.
for (int row = 0; row < array.length; row++)
{
if (row % 3 == 0)//If the row is divisible by 3 then print the plus(+) and minus(-) sign.
System.out.println("+-------+-------+-------+");
for (int col = 0; col < array[row].length; col++) {
if (col % 3 == 0)// If the column is divisible by 3 then print the or(|) symbol.
System.out.print("| ");
System.out.print(array[row][col]+ " ");
}
System.out.println("|");
}
System.out.println("+-------+-------+-------+");
}
The problem is that when you come back from the various recursive calls there is an instruction that modify the content of the array (see the comments):
for( int num = 1; num < 10; num++ )
{
if(validityRowColBox(array, row, col, num))
{
array[row][col] = num;
nextEmptyCell(array, row, col); // after you finish you come back from here
}
}
array[row][col] = 0; // ...and this will change the solution you found
Apparently this cause the array to come back to his original state.
I didn't look how the program works but avoiding to execute that instruction if we found the solution will return the correct array, for example:
public static boolean solve(int array[][], int row, int col) {
if (row > 8) {
printBoard(array);
return true;
}
if (array[row][col] != 0) {
return nextEmptyCell(array, row, col);
}
for (int num = 1; num < 10; num++) {
if (validityRowColBox(array, row, col, num)) {
array[row][col] = num;
if (nextEmptyCell(array, row, col)) {
return true; // if solution is found we just exit
}
}
}
array[row][col] = 0;
return false;
}
public static boolean nextEmptyCell(int array[][], int row, int col) {
if (col < 8) {
return solve(array, row, col + 1);
}
return solve(array, row + 1, 0);
}
I have to write a program that will read a picture and then print out the number of blocks inside it.
I have to read the picture as a binary matrix of the size r × c (number of rows times number of
columns).
The blocks are groups of one or more adjacent elements with the value 1.
Blocks are built exclusively of elements with value 1
Each element with value 1 is a part of some block
Adjacent elements with value 1 belong to the same block.
We only take into account the horizontal and vertical adjacency but not diagonal.
INPUT:
In the first line of the input we have the integers r and c, separated with one space.
Then we have the r lines, where each contains s 0's and 1's.
The numbers inside the individual lines are NOT separated by spaces.
The OUTPUT only print the number of blocks in the picture.
For example:
EXAMPLE 1
INPUT:
7 5
01000
00010
00000
10000
01000
00001
00100
OUTPUT:
6
EXAMPLE 2:
INPUT:
25 20
00010000000000000000
00010000000000000000
00010000000000000100
00000000000000000100
00011111111000000100
00000000000000000100
00000000000000000100
00000000000000000100
00000000000000000100
01111111111000000100
00000000000000000100
00000000000000100100
00000000000000100100
00000000000000100100
01000000000000100000
01000000000000100000
01000000000000100000
01000000000000100000
00000000000000100000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00011111111111100000
00000000000000000000
OUTPUT:
7
THE PROBLEM:
The problem that I have is that my program only works for inputs such as in example 1.
So pictures that only consist of blocks of size 1. But it doesnt work if there are multiples 1's in a picture, such as EXAMPLE 2.
In example 2 where the output should be 7(Blocks are elements of 1.They can either be vertial or horizontal).... my programs output is 30.
I don't know how to adjust the program in a correct manner so it will give me the correct input.
Thank you for your help in advance, here is my code that I am posting bellow.
import java.util.Scanner;
class Blocks{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int rowNum=sc.nextInt();
int columnNum=sc.nextInt();
char[][] matrix = new char[rowNum][columnNum];
int nbrOfBlocks = 0;
for (int a = 0; a < rowNum; a++) {
matrix[a] = sc.next().toCharArray();
int index = 0;
while (index < matrix[a].length) {
if (matrix[a][index] == '1') {
++nbrOfBlocks;
while (index < matrix[a].length && matrix[a][index] == '1') {
++index;
}
}
++index;
}
}
System.out.println(nbrOfBlocks);
}
}
EDIT: Ok, here is a solution that will work for complex shapes
public class BlockCounter {
public static void main(String[] args) {
Board board = null;
try {
board = new Board("in3.txt");
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
System.out.println("Block count: " + board.getBlockCount());
}
}
class Board {
ArrayList<String> data = new ArrayList<>();
boolean[][] used;
int colCount = 0;
public Board(String filename) throws FileNotFoundException, IOException {
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
data.add(line);
colCount = Math.max(colCount, line.length());
}
}
}
public int getBlockCount() {
used = new boolean[data.size()][colCount];
int count = 0;
for (int row = 0; row < data.size(); row++)
for (int col = 0; col < colCount; col++)
used[row][col] = peek(row, col) == '1';
for (int row = 0; row < data.size(); row++)
for (int col = 0; col < colCount; col++)
if (used[row][col]) {
fill(row, col);
count++;
}
used = null;
return count;
}
public char peek(int row, int col) {
if (row < 0 || row >= data.size() || col < 0)
return '0';
String rowData = data.get(row);
if (col >= rowData.length())
return '0';
return rowData.charAt(col);
}
public void fill(int row, int col) {
if (used[row][col]) {
used[row][col] = false;
if (row > 0 && used[row - 1][col])
fill(row - 1, col);
if (col > 0 && used[row][col - 1])
fill(row, col - 1);
if (col < colCount - 1 && used[row][col + 1])
fill(row, col + 1);
if (row < data.size() - 1 && used[row + 1][col])
fill(row + 1, col);
}
}
public int getRowCount() {
return data.size();
}
public int getColCount() {
return colCount;
}
}
Explanation:
When Board.getBlockCount() is called if creates a temporary array of booleans to work with so the original board is not messed up. Then it searches the entire board for "trues" (which correspond to '1's on the board). Every time a "true" is found, a flood fill algorithm clears the entire shape to which it is connected.
If you need more performance and less memory usage (specially stack) for larger boards, you can use another flood fill algorithm like in the example that follows. The big advantage here is that it doesn't use the stack for every pixel like the one above. It is considerably more complex though.
public class BlockCounter2 {
public static void main(String[] args) {
Board2 board = null;
try {
board = new Board2("in4.txt");
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
System.out.println("Block count: " + board.getBlockCount());
}
}
class Board2 {
ArrayList<String> data = new ArrayList<>();
boolean[][] used;
Deque<Point> pointStack = new LinkedList<>();
int colCount = 0;
public Board2(String filename) throws FileNotFoundException, IOException {
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
data.add(line);
colCount = Math.max(colCount, line.length());
}
}
}
public int getBlockCount() {
used = new boolean[data.size()][colCount];
int count = 0;
for (int row = 0; row < data.size(); row++)
for (int col = 0; col < colCount; col++)
used[row][col] = peek(row, col) == '1';
for (int row = 0; row < data.size(); row++)
for (int col = 0; col < colCount; col++)
if (used[row][col]) {
fill(row, col);
count++;
}
used = null;
return count;
}
public char peek(int row, int col) {
if (row < 0 || row >= data.size() || col < 0)
return '0';
String rowData = data.get(row);
if (col >= rowData.length())
return '0';
return rowData.charAt(col);
}
public void fill(int row, int col) {
pointStack.push(new Point(col, row));
Point p;
while (pointStack.size() > 0) {
p = pointStack.pop();
fillRow(p.y, p.x);
}
}
private void checkRow(int row, int col, int minCol, int maxCol) {
boolean uu = false;
for (int x = col; x < maxCol; x++) {
if (!uu && used[row][x])
pointStack.add(new Point(x, row));
uu = used[row][x];
}
uu = true;
for (int x = col; x > minCol; x--) {
if (!uu && used[row][x])
pointStack.add(new Point(x, row));
uu = used[row][x];
}
}
private void fillRow(int row, int col) {
int lx, rx;
if (used[row][col]) {
for (rx = col; rx < colCount; rx++)
if (used[row][rx])
used[row][rx] = false;
else
break;
for (lx = col - 1; lx >= 0; lx--)
if (used[row][lx])
used[row][lx] = false;
else
break;
if (row > 0)
checkRow(row - 1, col, lx, rx);
if (row < data.size() - 1)
checkRow(row + 1, col, lx, rx);
}
}
public int getRowCount() {
return data.size();
}
public int getColCount() {
return colCount;
}
}
EDIT2: Both solutions were made using input from txt files in order to make the debugging and testing easier for larger arrays. If you need them to work with user input (the same you have in your code) as well, just make the following changes:
Change the main method so it will listen from user input (again):
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int rowNum=sc.nextInt();
int columnNum=sc.nextInt(); // Note columnNum is not necessary
String[] matrix = new String[rowNum]; // I hope char[][] is not a requirement
for (int a = 0; a < rowNum; a++) // Read array data from user input
matrix[a] = sc.next();
sc.close();
Board2 board = new Board2(matrix); // Call the new constructor
System.out.println("Block count: " + board.getBlockCount());
}
Add a new constructor to Board2, that takes a String[] as input:
public Board2(String[] data) {
for (String line : data) {
this.data.add(line);
colCount = Math.max(colCount, line.length());
}
}
You may remove the previous constructor Board2(String filename) if it is not useful for you but it's not necessary.
Are you searching for this:
import java.util.Scanner;
class Blocks {
public static void removeBlock(char[][] matrix, int posX, int posY) {
if(0 <= posX && posX < matrix.length
&& 0 <= posY && posY < matrix[posX].length) {
if(matrix[posX][posY] == '0') {
return;
}
matrix[posX][posY] = '0';
} else {
return;
}
removeBlock(matrix, posX - 1, posY);
removeBlock(matrix, posX + 1, posY);
removeBlock(matrix, posX, posY - 1);
removeBlock(matrix, posX, posY + 1);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// read in
char[][] matrix = new char[sc.nextInt()][sc.nextInt()];
for(int a = 0; a < matrix.length; a++) {
matrix[a] = sc.next().toCharArray();
}
// calculate number of blocks
int nrBlocks = 0;
for(int i = 0; i < matrix.length; i++) {
for(int j = 0; j < matrix[i].length; j++) {
if(matrix[i][j] == '1') {
// we have found a block, so increment number of blocks
nrBlocks += 1;
// remove any 1's of the block from the array, so that they each block is not counted multiple times
removeBlock(matrix, i, j);
}
}
}
System.out.println(nrBlocks);
}
}
There's a linear time (in number of cells) solution to this. If I get time, I'll add the code to this answer, but if not the Wikipedia article (see EDIT below) gives pseudo code.
The idea is to scan line-by-line, assigning an incrementing unique run numbers to each runs of 1s we see (and changing the cell content to be that unique number) If in any run, the cells immediately above in the previous line were also 1 (that is, they now have a run number), then we know that their unique-run-number and the current unique-run number form part of a single block. So record that the run-above-run-number, and the current-run-number are equivalent (but don't bother to change anything on the board)
At the end, we have a count of the runs we've seen. and a set of equivalence relationships of unique-run-numbers. For each set of equivalent-numbers (say runs 3, 5, 14 form a block), we subtract from the run count the number of runs, minus 1 (in other words, replacing the multiple runs with a single block count).
I think I have some ideas to mitigate the worst case, but they're probably not worth it.
And that's the number of blocks.
The worst case for the equivalence classes is O(size of board) though (1-wide vertical blocks, with one space between them will do this). Fortunately, the entirely-black board will need only O(height of board) - each row will get one number, which will be marked equivalent with the next row.
EDIT: There's a Stackoverflow question about this already: can counting contiguous regions in a bitmap be improved over O(r * c)?
and it turns out I've just re-invented the two-pass "Connected Component Labelling" algorithm discussed on Wikipedia