【資料結構與演算法】回溯法解決N皇后問題,java程式碼實現
阿新 • • 發佈:2018-11-27
N皇后問題
問題描述
在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法,這稱為八皇后問題。
延伸一下,便為N皇后問題。
核心思想
解決N皇后問題有兩個關鍵點。一是如何進行放置棋子,二是如何驗證棋子是否符合要求。
因此,我們利用回溯法建立函式。
private static void NQueen(LinkedList<Location> list, int x, int y) {
if(list.size() == SIZE){ //當list元素個數為SIZE時,表示SIZE個皇后都擺放完畢,列印後即可退出函式。
printLocation(list); //列印皇后擺放方式
return ;
}
for(int i = x ; i < SIZE ; i++){
Location loc = new Location(i, y);
if(isLegalLoc(list, loc)){
list.offer(loc); //將第y列的皇后擺放好
NQueen(list, 0, y+1); //開始擺放y+1列的皇后,同樣從第0列開始擺放
list.pollLast(); //每次擺放完一個皇后後,都要將其撤回,再試探其它的擺法。
}
}
}
/**
* 判斷位置為loc的皇后是否合法
*/
private static boolean isLegalLoc(LinkedList<Location> list, Location loc) {
for(Location each : list){
if(loc. x == each.x || loc.y == each.y) //判斷是否在同一行或同一列
return false;
else if (Math.abs(loc.x - each.x) == Math.abs(loc.y - each.y)) //判斷是否在同斜線上
return false;
}
return true;
}
這裡對list.offer()進行補充。
- offer 屬於 offer in interface Deque,add 屬於 add in interface Collection。
- 當佇列為空時候,使用add方法會報錯,而offer方法會返回false。
- 作為List使用時,一般採用add / get方法來 壓入/獲取物件。
- 作為Queue使用時,才會採用 offer/poll/take等方法。
完整程式碼實現如下
import java.util.LinkedList;
import java.util.Scanner;
public class QueenN {
private static int SIZE = 0;//皇后的個數
private static int count = 0;//記錄擺放的方式數
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("請輸入你要解決幾個皇后的問題");
SIZE = input.nextInt();
input.close();
LinkedList<Location> list = new LinkedList<Location>();
NQueen(list, 0, 0); //從棋盤的第0行第0列開始
System.out.println(SIZE + "皇后共有 " + count + "種擺放方式");
}
static class Location{
int x;//對應棋盤的行
int y;//對應棋盤的列
Location(int x,int y){
this.x = x;
this.y = y;
}
public String toString() {
return "(" + x + "," + y + ")";
}
}
/**
* 主要函式,用回溯法。
*/
private static void NQueen(LinkedList<Location> list, int x, int y) {
if(list.size() == SIZE){ //當list元素個數為SIZE時,表示SIZE個皇后都擺放完畢,列印後即可退出函式。
printLocation(list); //列印皇后擺放方式
return ;
}
for(int i = x ; i < SIZE ; i++){
Location loc = new Location(i, y);
if(isLegalLoc(list, loc)){
list.offer(loc); //將第y列的皇后擺放好
NQueen(list, 0, y+1); //開始擺放y+1列的皇后,同樣從第0列開始擺放
list.pollLast(); //每次擺放完一個皇后後,都要將其撤回,再試探其它的擺法。
}
}
}
/**
* 判斷位置為loc的皇后是否合法
*/
private static boolean isLegalLoc(LinkedList<Location> list, Location loc) {
for(Location each : list){
if(loc.x == each.x || loc.y == each.y) //判斷是否在同一行或同一列
return false;
else if (Math.abs(loc.x - each.x) == Math.abs(loc.y - each.y)) //判斷是否在同斜線上
return false;
}
return true;
}
/**
* 列印皇后擺放方式
* @param list
*/
private static void printLocation(LinkedList<Location> list) {
String[][] show = new String[SIZE][SIZE];
for(int i = 0;i<SIZE;i++) {
for(int j = 0;j<SIZE;j++) {
show[i][j] = "0";
}
}
for(Location each : list){
System.out.print(each.toString() + "\t");
show[each.x][each.y] = "1";
}
System.out.println();
for(int i =0;i<SIZE;i++) {
for(int j=0;j<SIZE;j++) {
System.out.print(show[i][j] + " ");
}
System.out.println();
}
System.out.println();
count ++;
}
}