回溯算法经典案例——八皇后问题
题目描述:
在8*8的国际象棋上摆放八个皇后,使任意两个皇后都不能处于同一行,同一列或同一斜线上,问有多少种摆法
idea:
- 先把第一个黄后放在(1,1)
- 再把第二个皇后放在(2,1), (2,2),…直到找到一个解为止
- continue
- 只要得到一个答案,就会开始回溯,即将第一个皇后再放置在第一行的其他列,反复上述过程
核心代码
void Print();
void Print() {
for (int i = 0; i < n; i++) {
printf("%d ", p[i]+1);
}
printf("\n");
}
bool judge(int id);
bool judge(int id) {
for (int i = 0; i < id; i++) {
if (p[i] == p[id] || abs(i - id) == abs(p[i] - p[id])) {//判断同一列和斜着的情况
return false;
}
}
return true;
}
void check(int id);
void check(int id) {
if (id == n) {
cnt++;
if (cnt <= 3) {
Print();
}
return;
}
for (int i = 0; i < n; i++) {
p[id] = i;
if (judge(id)) {
check(id + 1);
}
}
}
例题
八皇后
这个题目我用上面这种做法,最后一个“13皇后”测试点超时
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int n, p[20],cnt;
void Print();
bool judge(int id);
void check(int id);
int main() {
scanf("%d", &n);
check(0);
printf("%d\n", cnt);
return 0;
}
void Print() {
for (int i = 0; i < n; i++) {
printf("%d ", p[i]+1);
}
printf("\n");
}
bool judge(int id) {
for (int i = 0; i < id; i++) {
if (p[i] == p[id] || abs(i - id) == abs(p[i] - p[id])) {
return false;
}
}
return true;
}
void check(int id) {
if (id == n) {
cnt++;
if (cnt <= 3) {
Print();
}
return;
}
for (int i = 0; i < n; i++) {
p[id] = i;
if (judge(id)) {
check(id + 1);
}
}
}
baidu了下
此题最好是回溯+标记
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int n, p[20],cnt,col[20],op1[1000],op2[1000];//记录列,两个斜对角
void Print();
void check(int id);
int main() {
scanf("%d", &n);
check(0);
printf("%d\n", cnt);
return 0;
}
void Print() {
for (int i = 0; i < n; i++) {
printf("%d ", p[i]+1);
}
printf("\n");
}
void check(int id) {
if (id == n) {
cnt++;
if (cnt <= 3) {
Print();
}
return;
}
for (int i = 0; i < n; i++) {
if (!col[i] && !op1[i + id] && !op2[id - i + n]) {
p[id] = i;
col[i] = 1;
op1[i + id] = 1;
op2[id - i + n] = 1;
check(id + 1);
col[i] = 0;
op1[i+id] = 0;
op2[id-i+n] = 0;
}
}
}