回溯法(排列樹)解決八(N)皇后問題

Tony_java發表於2018-07-03

問題描述:

八皇后問題是一個以國際象棋為背景的問題:如何能夠在8×8的國際象棋棋盤上放置八個皇后,使得任何一個皇后都無法直
接吃掉其他的皇后?為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。八皇后問題可以推廣為更一般的
n皇后擺放問題:這時棋盤的大小變為n×n,而皇后個數也變成n。當且僅當n = 1或n ≥ 4時問題有解。
                                                                      
                                                                        ---------來自<維基百科>
複製程式碼

個人思路:

回溯法(排列樹)解決八(N)皇后問題

  • max表示n個皇后 用array[n]表示皇后在第n+1行,array[n]列,比如array[0] = 8 意思為:該皇后位於第1行第8列的座標;

  • 思路:

  1. 排列樹與子集樹的區別在於子集樹不需要初始化而排列樹需要,此初始化內容為眾多可能解集合(注:是可能解,不一定為正確解)中的一個

  2. 初始化為a[]陣列(1-n隨意排列);

回溯法(排列樹)解決八(N)皇后問題

  1. 將a陣列的值向array中輸出,初始傳入n為0;表示該皇后在第一行,但具體哪列不確定,此時初始化的a陣列就起到了作用,a[n]表示在n+1行的第a[n]列, 將其賦值給array,即: array[n] = a[i];

    (因為a[]中只是可能性,所以要將所有可能性用for迴圈表示.即:for(int i = n;i < max ; i++);

    程式碼:

回溯法(排列樹)解決八(N)皇后問題

  1. 然後更新a陣列 swap(a,n,i) (意為 既然已經使用過a[i]那就用原本的a[n]替換a[i] 保證列值不重複)

  2. 更新後判斷該位置是否與已經存在的皇后的位置衝突(同斜線) 已經通過a陣列和n已經去除掉同行同列的可能;n保證不同行,a[i]保證不同列;

  3. 如果合法,則進入n+1;重複討論n+2個皇后的位置 /如果不合法,交換回之前位置(只有合法之後才能佔該列值) i++;

  4. 當i++到for迴圈結束,也就是說該皇后在這一行所有列中都沒有找到合適自己的位置,回退,即該方法執行結束,重新討論之前上個皇后的位置;

程式碼如下:

public class NQueen {

int max = 8;
int array[] = new int[max];
int[] a = { 8, 2, 3, 4, 5, 6, 7, 1 };

public void backtrack(int n) {
	if (n == max) {
		print();
		return;
	} else {
		for (int i = n; i < max; i++) {
			array[n] = a[i];
			swap(a, n, i);
			if (nice(n)) {
				backtrack(n + 1);
			}
			swap(a, n, i);
		}
	}

}

public boolean nice(int n) {
	for (int i = 0; i < n; i++) {
		if (Math.abs(n - i) == Math.abs(array[n] - array[i])) {
			return false;
		}
	}
	return true;
}

public void swap(int[] a, int i, int j) {
	int tem = a[i];
	a[i] = a[j];
	a[j] = tem;
}

int k = 0;

public void print() {
	++k;
	System.out.print("第" + k + "種解法:");
	for (int i = 0; i < array.length; i++) {
		System.out.print(array[i] + " ");
	}
	System.out.println();
}

public static void main(String[] args) {

	new NQueen().backtrack(0);
}
}
複製程式碼

相關文章