英文:
Using array.clone() and changing values, affects the original array too
问题
我编写了一个用于练习的程序,它生成带有0的emptyCellsPerBoard
个单元格(其余填充为随机数字)的numOfValidBoardsToCreate
个数独棋盘,然后解决这些棋盘。如果生成的棋盘无效或不可解,则尝试创建另一个棋盘,直到获得有效的棋盘为止。现在假设我们仅请求一个具有75个空单元格的棋盘及其解,以简化问题。
solve()
方法检查棋盘是否可解,如果可以解决,则解决它并返回 true。现在,由于在 for 循环的 if 语句中通过 isSolvableBoard()
检查每个棋盘的有效性,而 isSolvableBoard()
又调用了 solve()
,我不希望解决原始棋盘,因为我需要显示原始未解决的棋盘,然后是解决方案。所以我决定使用 sudokuBoard.clone()
复制原始棋盘,并在检查时使用该副本,之后将其忽略,因为在条件评估后将对其进行解决。我期望在第一次打印时,在 if() 语句内部的原始 sudokuBoard
不会被解决,但输出却是已解决的版本。我在这里漏掉了什么?
public static void main(String[] args) {
// ...(输入获取和时间计算部分略)
int[][] sudokuBoard;
int[][] copyOfBoard;
for (int i = 1; i <= numOfValidBoardsToCreate; i++) {
sudokuBoard = solver.generateSudokuBoard(emptyCellsPerBoard);
// 创建棋盘的副本,用于传递给 isSolvableBoard() 以在不改变棋盘的情况下测试条件
copyOfBoard = sudokuBoard.clone();
if (solver.isSolvableBoard(copyOfBoard)) {
System.out.println("Board #" + i);
solver.printBoard(sudokuBoard);
System.out.println("Solution of board #" + i);
solver.solve(sudokuBoard);
solver.printBoard(sudokuBoard);
} else {
numOfUnsolvableBoards++;
numOfInvalidBoards++;
i--; // 如果未达到末尾,再次运行循环
}
}
// ...(打印最终消息和时间部分略)
}
boolean solve(int[][] board) {
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
if (board[row][column] == NO_VALUE) {
for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
board[row][column] = k;
if (isValid(board, row, column) && solve(board)) {
return true;
}
board[row][column] = NO_VALUE;
}
return false;
}
}
}
return true;
}
/**
* 检查一个数独棋盘是否有效并可解。
*
* @param board 给定的棋盘
* @return 如果有效或者不可解则返回 true。
*/
boolean isSolvableBoard(int[][] board) {
return isValidBoard(board) && solve(board);
}
/**
* 检查给定的数独棋盘是否有效。
*
* @param brd 9x9 棋盘
* @return 如果有效则返回 true,否则返回 false。
*/
private boolean isValidBoard(int[][] brd) {
for (int i = BOARD_START_INDEX; i < BOARD_SIZE; i++) {
for (int j = BOARD_START_INDEX; j < BOARD_SIZE; j++) {
try {
if (!isValid(brd, i, j)) return false;
} catch (ArrayIndexOutOfBoundsException e) { // 如果给定单元格的值大于9,会抛出异常,因此处理它
return false;
}
}
}
return true;
}
英文:
I have written a program for an exercise that generates numOfValidBoardsToCreate
Sudoku boards with emptyCellsPerBoard
cells with 0s (fills the rest with random numbers) and then solves them. If a generated board isn't valid or solvable it tries to create another one until it gets it. Now let's say we request just one board with 75 empty cells and its solution for the sake of simplicity.
The solve()
method checks if a board is solvable and if so it solves it and returns true. Now, since when i check for each board's validity in the if statement of the for loop using isSolvableBoard()
which in turn calls solve()
, i don't want to solve the original board since i'm going to need to display the original unsolved one and then the solution. So i decided to use sudokuBoard.clone()
to make a copy of the original one and use that for the check and disregard it since it's going to be solved after the condition is evaluated. I'd expect that the original sudokuBoard
inside the if() statement wouldn't be solved when i print it the first time but the output is the solved version. What am i missing here?
public static void main(String[] args) {
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
// Get the required input from the user
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the number of empty cells that the board should have:");
int emptyCellsPerBoard = scanner.nextInt();
System.out.println("Enter how many boards the app should create and solve:");
int numOfValidBoardsToCreate = scanner.nextInt();
// extra data to keep track of for printing purposes
int numOfInvalidBoards = 0;
int numOfUnsolvableBoards = 0;
// finding the time before the operation is executed
long start = System.currentTimeMillis();
int[][] sudokuBoard;
int[][] copyOfBoard;
for (int i = 1; i <= numOfValidBoardsToCreate; i++) {
sudokuBoard = solver.generateSudokuBoard(emptyCellsPerBoard);
// Create a copy of the board to pass to isSolvableBoard to test the condition without altering the board
copyOfBoard = sudokuBoard.clone();
if (solver.isSolvableBoard(copyOfBoard)) {
System.out.println("Board #"+i);
solver.printBoard(sudokuBoard);
System.out.println("Solution of board #"+i);
solver.solve(sudokuBoard);
solver.printBoard(sudokuBoard);
} else {
numOfUnsolvableBoards++;
numOfInvalidBoards++;
i--; // run the loop again if we haven't reached the end
}
}
// finding the time after the operation is executed
long end = System.currentTimeMillis();
//finding the time difference and converting it into seconds
float sec = (end - start) / 1000F;
// Print final message
System.out.println("Empty Cells per board: " + emptyCellsPerBoard + "\nValid boards created: " + numOfValidBoardsToCreate + "\nInvalid boards created: "
+ numOfInvalidBoards + "\nUnsolvable boards created: " + numOfUnsolvableBoards + "\nElapsed time: " + sec + " seconds");
}
}
boolean solve(int[][] board) {
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
if (board[row][column] == NO_VALUE) {
for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
board[row][column] = k;
if (isValid(board, row, column) && solve(board)) {
return true;
}
board[row][column] = NO_VALUE;
}
return false;
}
}
}
return true;
}
/**
* Checks if a Sudoku board is valid and solvable.
*
* @param board The given board
* @return True if it is or false otherwise.
*/
boolean isSolvableBoard(int[][] board) {
return isValidBoard(board) && solve(board);
}
/**
* Checks if the given sudoku board is valid.
*
* @param brd The 9x9 board
* @return True if it's valid or false otherwise.
*/
private boolean isValidBoard(int[][] brd) {
for (int i = BOARD_START_INDEX; i < BOARD_SIZE; i++) {
for (int j = BOARD_START_INDEX; j < BOARD_SIZE; j++) {
try {
if (!isValid(brd, i, j)) return false;
} catch (ArrayIndexOutOfBoundsException e) { // if a given cell has a value > 9, an exception is thrown, so handle it
return false;
}
}
}
return true;
}
答案1
得分: 0
以下是翻译好的内容:
事实证明,一个好的解决方案如下:
for(int j=0; j < 9; j++) {
copyOfBoard[j] = Arrays.copyOf(sudokuBoard[j], sudokuBoard.length); // 对子数组进行深拷贝
}
基本上,这段代码对二维数组的每个子数组执行深拷贝操作。
英文:
Turns out a good solution is the following:
for(int j=0; j <9; j++) {
copyOfBoard[j] = Arrays.copyOf(sudokuBoard[j], sudokuBoard.length); // deep copy of the subarray
}
Which basically performs a deep copy of each subarray of the 2D array.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论