(一)八皇后问题

(1)回溯

#include <iostream>
#include <string>

#define MAXN 100

using namespace std;

int tot = 0, n = 8;
int C[MAXN];

void search(int cur) {
if(cur == n) ++tot; //递归边界,仅仅要走到了这里。全部皇后必定不冲突
else for(int i = 0; i < n; ++i) {
int ok = 1;
C[cur] = i; //尝试把第cur行的皇后放在第i列
for(int j = 0; j < cur; ++j) { //检查是否和前面的皇后冲突
if(C[cur] == C[j] || cur-C[cur] == j-C[j] || cur+C[cur] == j+C[j]) {
ok = 0;
break;
}
}
if(ok) search(cur+1); //假设合法,则继续递归
}
}

int main() {
search(0);
cout << tot << endl;
return 0;
}




(2)利用二维数组优化的回溯法

#include <iostream>
#include <string>

#define MAXN 100

using namespace std;

int tot = 0, n = 8;
int vis[3][MAXN], C[MAXN];

void search(int cur) {
if(cur == n) ++tot;
else for(int i = 0; i < n; ++i) {
if(!vis[0][i] && !vis[1][cur+i] && !vis[2][cur-i+n]) { //利用二维数组直接推断
C[cur] = i;
vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1; //改动全局变量
search(cur+1);
vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0; //这里一定要改回来!
}
}
}

int main() {
memset(vis, 0, sizeof(vis));
search(0);
cout << tot << endl;
return 0;
}


在上面的程序中,vis数组表示已经放置的皇后占领了哪些列、主对角线和副对角线。

一般的在回溯法中,假设改动了全局变量vis数组,那么递归调用结束后一定要改动回来!由于在解答树中,假设下一层不满足条件,那么就须要回溯。那么就要把改动过的vis给改回来,那样,才干继续进行下一次的推断!!!


(二)素数环

题目:输入正整数n,把整数1。2,3,...,n组成一个环。使得相邻两个整数之和均为素数。

输出时从整数1開始逆时针排列。

同一个环应该恰好输出一次。

典型的回溯法,代码例如以下:

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 1000;
int isp[MAXN], vis[MAXN], A[MAXN], n;

int is_prime(int x) { //推断一个数是否为素数
for(int i = 2; i*i <= x; ++i) {
if(x % i == 0) return 0;
}
return 1;
}

void dfs(int cur) {
if(cur == n && isp[A[0] + A[n-1]]) {
for(int i = 0; i < n; ++i) cout << A[i] << " ";
cout << endl;
}else {
for(int i = 2; i <= n; ++i) {
if(!vis[i] && isp[i + A[cur-1]]) {
A[cur] = i; //数字i满足条件,所以第cur个位置能够放数字i
vis[i] = 1;
dfs(cur+1);
vis[i] = 0; //跟上题一样。一定不能忘记把vis的值改回来,原因见上一题的代码凝视
}
}
}
}

int main() {
memset(vis, 0, sizeof(vis)); //递归调用之前,一定要把vis函数清0
cin >> n;
for(int i = 2; i <= 2*n; ++i) isp[i] = is_prime(i); //推断一个数不是质数。为了方便后推断
A[0] = 1; //从标题中的规定的第一个数字1开始
dfs(1); //所以递归调用位置的1开始,而不是从位置0开始,因为数字第一位置已被确定是1
return 0;
}