回溯法(8皇後問題)
阿新 • • 發佈:2017-10-22
spa out class 分享 過程 img names 必須 pac
遞歸函數不再調用它本身,而是返回上一層調用,這種現象稱為回溯。
表現在解答樹中就是一個結點本來應該有的分支因為不滿足條件而沒有接續產生分支。
八皇後問題:在8*8的棋盤上,放置8個皇後,使其不互相攻擊,皇後的攻擊範圍為同行同列和同對角線,找出所有解。
思考可知:每一行只能放一個,每一列也只能放一個。
用c[i]表示第i行的皇後的列數,行數、列數範圍都是0~7。
問題變成了0~7的排列問題。枚舉數為8!= 40320個,枚舉數不會超過它。
又因為位置不同行不同列不同對角線的限制,一些排列不會把整個排列都列出就可以判斷不符合情況(這也是遞歸構造和直接枚舉的不同,遞歸構造可以把生成和檢查的過程有機結合起來,而直接枚舉必須生成所有可能的解,然後一一檢查),表現在解答樹中,就是只有滿足條件的結點有分支,不滿足條件的沒有分支而是回溯了。
同行同列的判斷條件好想,同對角線的條件是:行數差的絕對值等於列數差的絕對值。判斷時用當前的行、列數和已經排好的行、列數比較。(祖父結點是排好的/A[0]~A[cur - 1]是排好的)
#include<iostream> using namespace std; void f(int A[], int cur, int n) { if(cur == 8) { for(int i = 0; i < 8 ; i ++) { cout << A[i] << ‘,‘; } cout<< endl; return ; } for(int i = 0; i < n; i++) { bool flag = true; for(int j = 0; j < cur; j ++) { if(i == A[j]) { flag = false; break; } if(cur - j == i - A[j] || cur - j == A[j] - i) { flag= false; break; } } if(flag) { A[cur] = i; f(A, cur + 1, n); } } } int main() { int A[8]; f(A, 0, 8); return 0; }
回溯法(8皇後問題)