八皇后問題(C語言版本)
阿新 • • 發佈:2019-01-01
八皇后問題是一個古老而著名的問題,是回溯演算法的典型例題。該問題是十九世紀著名的數學家高斯1850年提出:在8X8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線(對角線)上,問有多少種擺法。
解決方法1
下面的C程式碼可以解決N皇后問題,8皇后問題的解是92。
程式執行部分結果截圖:#include <stdio.h> #include <stdlib.h> #define max 8 int queen[max], sum=0; /* max為棋盤最大座標 */ void show() /* 輸出所有皇后的座標 */ { int i; for(i = 0; i < max; i++) { printf("(%d,%d) ", i, queen[i]); } printf("\n"); sum++; } int check(int n) /* 檢查當前列能否放置皇后 */ { int i; for(i = 0; i < n; i++) /* 檢查橫排和對角線上是否可以放置皇后 */ { if(queen[i] == queen[n] || abs(queen[i] - queen[n]) == (n - i)) { return 1; } } return 0; } void put(int n) /* 回溯嘗試皇后位置,n為橫座標 */ { int i; for(i = 0; i < max; i++) { queen[n] = i; /* 將皇后擺到當前迴圈到的位置 */ if(!check(n)) { if(n == max - 1) { show(); /* 如果全部擺好,則輸出所有皇后的座標 */ } else { put(n + 1); /* 否則繼續擺放下一個皇后 */ } } } } int main() { put(0); /* 從橫座標為0開始依次嘗試 */ printf("%d", sum); return 0; }
解決方法2
由於8個皇后的任意兩個不能處在同一行,那麼肯定是每一個皇后佔據一行。於是我們可以定義一個數組ColumnIndex[8],陣列中第i個數字表示位於第i行的皇后的列號。先把陣列ColumnIndex的8個數字分別用0~7初始化,接下來就是對陣列ColumnIndex做全排列。因為我們是用不同的數字初始化陣列,所以任意兩個皇后肯定不同列。我們只需要判斷每一個排列對應的8個皇后是不是在同一對角線上,也就是對於陣列的兩個下標i和j,是不是 i-j==ColumnIndex[i]-ColumnIndex[j]或者 j-i==ColumnIndex[i]-ColumnIndex[j]。int queenNumber=0; //判斷是否是合法的序列 bool JudgeValid(int* array,int length){ for(int i=0;i<length-1;i++) for(int j=i+1;j<length;j++){ if(i-j==array[i]-array[j] || j-i==array[i]-array[j]) return false; } return true; } //獲得皇后問題的全排列 void QueuePermutation(int* array,int beginIndex,int length){ if(beginIndex==length){ if(JudgeValid(array,length)) ++queenNumber; }else{ for(int curSub=beginIndex;curSub!=length;curSub++){ int temp=array[beginIndex]; array[beginIndex]=array[curSub]; array[curSub]=temp; QueuePermutation(array,beginIndex+1,length); temp=array[beginIndex]; array[beginIndex]=array[curSub]; array[curSub]=temp; } } } //可以解決N皇后問題 void QueueProgram(int length){ int *array=new int[length]; for(int i=0;i<length;i++) array[i]=i;//初始化陣列 QueuePermutation(array,0,length); }
結果輸出為:92。對於合法排列,可以輸出皇后放置的詳細位置。