N皇后和数独总结

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;

	}

}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值