N皇后问题:
解法参考自《程序员面试金典》235页,这本书上的解答是用一维数组代替二维数组,因为每一行只能放一个皇后,那么我们以columns数组来表示皇后的位置,假如columns[i]=j,表示第i行的皇后位于第j列。接下来直接上代码:
import java.util.*;
public class NQueens {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
List<int[]> res = new ArrayList<>();
int[] columns = new int[n];
place(0, n, columns, res);
for (int i = 0; i < res.size(); i++) {
System.out.println("Sol" + (i + 1) + ":");
print(res.get(i));
}
}
scanner.close();
}
public static void place(int cur, int n, int[] columns, List<int[]> res) {
if (cur == n) {
res.add(columns.clone());
return;
}
for (int i = 0; i < n; i++) {
if (isValid(columns, cur, i)) {
columns[cur] = i;
place(cur + 1, n, columns, res);
}
}
}
public static boolean isValid(int[] columns, int row, int col) {
for (int i = 0; i < row; i++) {
if (columns[i] == col || Math.abs(columns[i] - col) == row - i) {
return false;
}
}
return true;
}
public static void print(int[] columns) {
for (int i = 0; i < columns.length; i++) {
for (int j = 0; j < columns.length; j++) {
if (j != columns[i]) {
System.out.print('.');
} else {
System.out.print('Q');
}
}
System.out.println();
}
}
}
输入:
8
输出:
数独问题:
跟八皇后类似,但是这里必须使用二维数组,同时必须有一个回退过程(这样才能使上层做多种尝试),即board[row][col] = ‘.’;这一条语句的作用,这种情形在递归中非常常见。直接上代码:
import java.util.*;
public class Sudoku {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
char[][] board = new char[9][9];
for (int i = 0; i < 9; i++) {
String str = scanner.next();
for (int j = 0; j < 9; j++) {
board[i][j] = str.charAt(j);
}
}
List<char[][]> res = new ArrayList<>();
solve(board, 0, res);
for (int i = 0; i < res.size(); i++) {
System.out.println("Sol" + (i + 1) + ":");
char[][] sol = res.get(i);
for (int j = 0; j < 9; j++) {
System.out.println(String.valueOf(sol[j]));
}
}
}
scanner.close();
}
public static void solve(char[][] board, int n, List<char[][]> res) {
if (n == 81) {
char[][] temp = new char[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
temp[i][j] = board[i][j];
}
}
res.add(temp);
return;
}
int row = n / 9;
int col = n % 9;
if (board[row][col] != '.') {
solve(board, n + 1, res);
} else {
for (char c = '1'; c <= '9'; c++) {
if (isValid(board, row, col, c)) {
board[row][col] = c;
solve(board, n + 1, res);
board[row][col] = '.';
}
}
}
}
public static boolean isValid(char[][] board, int row, int col, char val) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == val || board[i][col] == val) {
return false;
}
}
int m = row / 3 * 3;
int n = col / 3 * 3;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[m + i][n + j] == val) {
return false;
}
}
}
return true;
}
}
输入:
输出:
下面考虑另一个问题,如果要求是,只需要输出一种解,又该怎么办呢,其实只要对递归函数稍加修改即可,这里的关键是,只要找到一种可行解,就立即一层一层往上退出。那这里把返回类型改为布尔类型,如果找到一种解,就一层层返回true,反之我们继续往后尝试,如果所有可能都尝试一遍,没有可行解,那么就返回false。下面对两个问题都进行修改,主要是修改返回类型,以及在对应的地方加上返回语句,上代码:
N皇后:
代码:
import java.util.*;
public class NQueens2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
List<int[]> res = new ArrayList<>();
int[] columns = new int[n];
place(0, n, columns, res);
for (int i = 0; i < res.size(); i++) {
System.out.println("Sol" + (i + 1) + ":");
print(res.get(i));
}
}
scanner.close();
}
public static boolean place(int cur, int n, int[] columns, List<int[]> res) {
if (cur == n) {
res.add(columns.clone());
return true;
}
for (int i = 0; i < n; i++) {
if (isValid(columns, cur, i)) {
columns[cur] = i;
if (place(cur + 1, n, columns, res)) {
return true;
}
}
}
return false;
}
public static boolean isValid(int[] columns, int row, int col) {
for (int i = 0; i < row; i++) {
if (columns[i] == col || Math.abs(columns[i] - col) == row - i) {
return false;
}
}
return true;
}
public static void print(int[] columns) {
for (int i = 0; i < columns.length; i++) {
for (int j = 0; j < columns.length; j++) {
if (j != columns[i]) {
System.out.print('.');
} else {
System.out.print('Q');
}
}
System.out.println();
}
}
}
运行结果:
数独:
代码:
import java.util.*;
public class Sudoku2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
char[][] board = new char[9][9];
for (int i = 0; i < 9; i++) {
String str = scanner.next();
for (int j = 0; j < 9; j++) {
board[i][j] = str.charAt(j);
}
}
List<char[][]> res = new ArrayList<>();
solve(board, 0, res);
for (int i = 0; i < res.size(); i++) {
System.out.println("Sol" + (i + 1) + ":");
char[][] sol = res.get(i);
for (int j = 0; j < 9; j++) {
System.out.println(String.valueOf(sol[j]));
}
}
}
scanner.close();
}
public static boolean solve(char[][] board, int n, List<char[][]> res) {
if (n == 81) {
char[][] temp = new char[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
temp[i][j] = board[i][j];
}
}
res.add(temp);
return true;
}
int row = n / 9;
int col = n % 9;
if (board[row][col] != '.') {
if (solve(board, n + 1, res)) {
return true;
}
return false;
} else {
for (char c = '1'; c <= '9'; c++) {
if (isValid(board, row, col, c)) {
board[row][col] = c;
if (solve(board, n + 1, res)) {
return true;
}
board[row][col] = '.';
}
}
return false;
}
}
public static boolean isValid(char[][] board, int row, int col, char val) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == val || board[i][col] == val) {
return false;
}
}
int m = row / 3 * 3;
int n = col / 3 * 3;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[m + i][n + j] == val) {
return false;
}
}
}
return true;
}
}
运行结果: