1. 程式人生 > >【資料結構與演算法】回溯法解決N皇后問題,java程式碼實現

【資料結構與演算法】回溯法解決N皇后問題,java程式碼實現

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 ++;
    }

}