【深度优先算法】
沿着某条路径遍历,直到末端,然后回溯,再遍历另一条路径(走没有走过的岔路口)做同样的遍历,直到所有的节点都被访问,即回溯到源节点并且源节点已无未被访问的子节点。
库克船长的宝藏
描述
皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 × 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。
对于某个满足要求的8皇后的摆放方法,每种方案顺序输出皇后所在的列号,各个数之间没有空格隔开。
输入描述
此题无输入
输出描述
92行,每行表示一种放置方案,每种方案顺序输出皇后所在的列号。按给定顺序和格式输出八皇后的解(见样例)。
用例输入 1
无输入
用例输出 1
15863724
…(省略号)
84136275
程序如下:
#include<iostream>
using namespace std;
int mp[9][9] = {}; //存储皇后位置
int b[9], c[16], d[17]; //b:列 c:左对角线 d:右对角线
void print() {
for (int i = 1; i <= 8; i++) {
for (int j = 1; j <= 8; j++) {
if (mp[i][j] == 1) cout << j; //输出皇后所在的列号
}
}
cout << endl;
}
void dfs(int i) { //第i行开始
if (i == 9) { //搜索到第9行时,说明前8行放置完毕
print();//自定义输出函数,输出该放置方案
return ;
}
for (int j = 1; j <= 8; j++) { //循环第i行所有列
if (b[j] == 0 && c[i - j + 8] == 0 && d[i + j] == 0) {
mp[i][j] = 1; //放置皇后
//标识行、列、左对角线、右对角线不能再放置皇后
b[j] = c[i - j + 8] = d[i + j] = 1;
dfs(i + 1); //下一行
mp[i][j] = 0; //清空第i行,第j列皇后
b[j] = c[i - j + 8] = d[i + j] = 0; //清空皇后攻击范围
}
}
}
int main() {
dfs(1);//第一行开始放置皇后
return 0;
}
围城面积
描述
编程计算由“”号围成的下列图形的面积。面积计算方法是统计号所围成的闭合曲线中水平线和垂直线交点的数目。如下图所示,在10×10的二维数组中,有“*”围住了15个点,因此面积为15。
输入描述
10×10 的图形。
输出描述
输出面积。
用例输入 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 1 0
0 1 0 1 0 1 0 0 1 0
0 1 0 0 1 1 0 1 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
用例输出 1
15
*/
#include <iostream>
using namespace std;
int mp[12][12]; // 地图矩阵
int ans;
int dx[4] = {-1, 0, 1, 0}; // 上右下左四个方向的横坐标偏移量
int dy[4] = {0, 1, 0, -1}; // 上右下左四个方向的纵坐标偏移量
// 深度优先搜索
void dfs(int x, int y) {
for (int i = 0; i < 4; i++) {
int nx = x + dx[i]; // 计算下一步的横坐标
int ny = y + dy[i]; // 计算下一步的纵坐标
if (nx >= 0 && nx < 12 && ny >= 0 && ny < 12 && mp[nx][ny] == 0) { // 判断下一步是否在地图范围内且可达
mp[nx][ny] = 2; // 标记该位置已经访问过
dfs(nx, ny); // 继续从下一个位置开始搜索
}
}
}
int main() {
for (int i = 1; i <= 10; i++) { // 输入地图信息
for (int j = 1; j <= 10; j++)
cin >> mp[i][j];
}
mp[0][0] = 2; // 标记起始位置已经访问过
dfs(0, 0); // 从起始位置开始进行深度优先搜索
for (int i = 1; i <= 10; i++) { // 统计未访问过的位置数量
for (int j = 1; j <= 10; j++)
if (mp[i][j] == 0)
ans++;
}
cout << ans; // 输出未访问过的位置数量
return 0;
}
寻宝
描述
侠盗 Hank 经过千难万险终于来到了恶人岛,为了拿到恶人岛的宝座去帮助穷人,Hank 先对恶人岛进行了侦查,发现恶人岛有一个迷阵,宝藏摆在了迷阵的深处。迷阵由 M×N 个方 格组成,有的方格内有可以发现 Hank 的守卫,而有的方格内则是安全。为了展现自己的实 力,Hank 决定不仅要拿走恶人岛的宝藏,还要给他们留一封信,告诉恶人自己有 g 种方法 找到宝藏。现在要求你来帮助他实现这个目标。
迷阵越大,守卫越多。
输入描述
输入有一组测试数据,以两个非零整数 N 和 M 开始,两者均不大于20。N表示迷阵行数, M表示迷阵列数。接下来有 N 行, 每行包含 M 个字符,不同字符分别代表不同含义:
‘@’:Hank 所在的位置;
‘.’:可以安全通行的方格;
‘#’:有守卫的方格;
‘*’:宝藏所在位置。
输出描述
一个整数 g,表示 Hank 有 g 种方法可以找到宝藏。如果他不可能找到宝藏, 则输出-1。
用例输入 1
8 8
.@##…#
#…#.#
#.#.##…
…#.###.
#.#…#.
…###.#.
…#.*…
.#…###
用例输出 1
4
#include <bits/stdc++.h>
using namespace std;
int m, n, sx, sy, ans, flag;
char mp[40][40]; // 地图矩阵
int vis[40][40]; // 访问标记数组
int dx[4] = {-1, 0, 1, 0}; // 上右下左四个方向的偏移量
int dy[4] = {0, 1, 0, -1};
// 深度优先搜索
void dfs(int x, int y) {
if (mp[x][y] == '*') { // 如果当前位置是目标位置
ans++; // 目标数量加一
flag = 1; // 设置标志为1,表示找到了路径
return;
}
for (int i = 0; i < 4; i++) { // 遍历四个方向
int xx = x + dx[i];
int yy = y + dy[i];
if (xx >= 0 && xx < n && yy >= 0 && yy < m) { // 判断下一步是否在地图范围内
if (mp[xx][yy] != '#' && vis[xx][yy] == 0) { // 判断下一步是否可达且未访问过
vis[xx][yy] = 1; // 标记该位置已经访问过
dfs(xx, yy); // 继续从下一个位置开始搜索
vis[xx][yy] = 0; // 恢复该位置的访问状态,用于回溯
}
}
}
}
int main() {
cin >> n >> m; // 输入行数和列数
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> mp[i][j]; // 输入地图信息
if (mp[i][j] == '@') { // 记录起始位置
sx = i;
sy = j;
}
}
}
vis[sx][sy] = 1; // 标记起始位置已经访问过
dfs(sx, sy); // 从起始位置开始进行深度优先搜索
if (flag) { // 如果找到了路径,输出目标数量
cout << ans;
} else { // 否则输出-1
cout << -1;
}
return 0;
}
N个数的所有情况的全排列
描述:
输入一个正整数N,输出N个数的所有情况的全排列。
输入描述:
输入一个正整数N。(1<=N<10)
输出描述:
N个数的所有情况的全排列
用例输入:
3
用例输出:
1
12
123
13
132
2
21
213
23
231
3
31
312
32
321
#include<bits/stdc++.h>
using namespace std;
int a[11] = {0}; // 保存数列的数组, 默认每个位置都是0
bool book[11] = {0}; // 记录一个数有没有在数组里
int n; // n个数
void print(int pos) {
for (int i = 1; i <= pos; i++) // 输出数列
printf("%d", a[i]);
printf("\n");
}
void dfs(int pos) {
if (pos == n + 1) return; // 数列填完,递归结束
for (int i = 1; i <= n; i++) { // 遍历所有可能的数
if (book[i] == 0) { // 如果该数没有被使用过
a[pos] = i; // 将该数放入当前位置
book[i] = 1; // 标记该数已被使用
print(pos); // 输出当前数列
dfs(pos + 1); // 向a[pos+1]填数,进入下一层递归
a[pos] = 0; // 回溯,将当前位置置为0
book[i] = 0; // 收回标记,该数未被使用
}
}
}
int main() {
scanf("%d", &n); // 输入n
dfs(1); // 从第一个位置开始递归填数
return 0;
}
字母全排列
给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。
我们假设对于小写字母有‘a’ <‘b’ < … <‘y’<‘z’,而且给定的字符串中的字母已经按照从小到大的顺序排列。
输入描述:
只有一行,是一个由不同的小写字母组成的字符串,已知字符串的长度在1到6之间。
用例输入:
abc
用例输出:
abc
acb
bac
bca
cab
cba
#include <bits/stdc++.h>
using namespace std;
bool b[101];
int len; //存储长度
char c[101],a[101];
void q(){
for(int i=0;i<len;i++){
cout<<c[i];
}
cout<<endl;
}
void dfs(int x){
for(int i=0;i<len;i++){
if(b[i]==0){ //如果该位没有放
b[i]=1; //将该位标记为放了
c[x]=a[i]; //往里面填字符
if(x==len-1){
q(); //如果填满了,就输出一组解
}
else{
dfs(x+1); //递归放置下一个数
}
b[i]=0; //回溯
}
}
}
int main()
{
gets(a); //输入字符串
len=strlen(a); //去到长度
dfs(0); //深搜
return 0;
}