DFS入门——八皇后问题输出方案
题目出处:《信息学奥赛一本通》第五章上机练习2
题目描述
要在国际象棋棋盘(\(8 \times 8\) 的棋盘)中放 \(8\) 个皇后,使任意两个皇后都不能互相吃。(提示:皇后能吃同一行、同一列、同一对角线的任意棋子。)
输入格式
无输入。
输出格式
按给定顺序和格式输出所有八皇后问题的解(见样例输出)
样例输入
无输入。
样例输出
No. 1
1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0
No. 2
1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1
0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0
... 以下省略
题目分析
这道题其实和我们之前的“八皇后问题”非常类似。
只不过之前只是计数,而我们这里需要输出所有方案,所以在原来的基础上添加一个输出方案的函数 output()
即可。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
int ans[9], cnt; // ans[i]用于记录第i行皇后列号,cnt用于记录方案数
// attack函数用于判断(x1,y1)和(x2,y2)两个点是否会互相攻击
// 返回true:会互相攻击到;返回false:不会互相攻击到
bool attack(int x1, int y1, int x2, int y2) {
return x1==x2||y1==y2||abs(x1-x2)==abs(y1-y2);
}
// output函数用于输出一种方案
void output() { // 新增的用于输出方案的函数
cnt ++; // 找到一个方案,cnt++
cout << "No. " << cnt << endl; // 输出方案id
for (int i = 1; i <= 8; i ++) { // 输出方案
for (int j = 1; j <= 8; j ++)
cout << (j > 1 ? " " : "") << (j == ans[i]);
cout << endl;
}
}
// f函数用于在第id行尝试性地放一个i,然后递归地去id+1行放
void f(int id) {
if (id > 8) { // 说明前8行已经放好了
output(); // 调用output函数,因为这里要输出了
return; // 程序可直接返回
}
for (int i = 1; i <= 8; i ++) { // 尝试在第id行第i列放皇后
bool flag = true; // flag用于标识是否能放
for (int j = 1; j < id; j ++) {
if (attack(id, i, j, ans[j])) { // (id,i)和(j,ans[j])冲突
flag = false; // 将flag设为false标识不能放
break;
}
}
if (flag) { // 如果循环结束flag仍为true说明i能放
ans[id] = i; // 能放就先放上
f(id+1); // 然后递归进行下一行的放置
}
}
}
int main() {
f(1); // 从第1行开始放
return 0;
}