目录
1.概念
深度优先搜索(DFS),一条路走到黑,回溯,遍历所有节点
广度优先搜索(BFS),层层递进,遍历所有节点
深搜和广搜可以提高枚举的效率,是我们解决问题的重要工具
2.DFS->八皇后
问题描述:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。著名数学家高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。今天,我们可以用计算机来AC这个高斯回答错误的问题。
我们可以进行一下模拟,例如现在将前三行棋子的位置输出,并输出最终结果数。可以定义一个二维数组表示棋盘,不过显然那样会增加时间复杂度,不妨直接开一个一维数组a[i]=j表示第i行皇后放在第j列上,用三个b数组判断皇后是否可以放置,然后就可以利用DFS来解决这道题目了。
代码:
#include <iostream>
using namespace std;
//DFS算法 八皇后
#define maxn 100
int a[maxn], n, ans = 0;
int b1[maxn], b2[maxn], b3[maxn];
//b1记录第i列,b2记录x+y=i斜列,b3记录x-y+15=i斜列 ->是否可放
void dfs(int x)//第x行皇后放哪
{
if (x > n)
{
ans++;
if (ans <= 3)//输出了前三种,也可以输出所有种情况
{
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
}
return;
}
for(int i=1;i<=n;i++)
if (b1[i] == 0 && b2[x + i] == 0 && b3[x - i + 15] == 0)//可放置
{
a[x] = i;//第x行皇后放在第i列上
b1[i] = 1;
b2[x + i] = 1;
b3[x - i + 15] = 1;
dfs(x + 1);//递归下一行
b1[i] = 0; b2[x + i] = 0; b3[x - i + 15] = 0;//回溯
}
}
int main()
{
cin >> n;
dfs(1);
cout << ans;
return 0;
}
也可以将所有可能的情况打表输出:
#include<iostream>
//这段代码时间复杂度有点高qwq
using namespace std;
int f[16][16],cnt=0;
int n;
void print()
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
cout << f[i][j] << " ";
cout << endl;
}
cout << endl;
}
bool check(int x,int y)
{
for (int i = 1; i <= n; i++)
if (f[i][y] == 1)
return false;
for(int i=1;i<=n;i++)
for (int j = 1; j <= n; j++)
{
if (f[i][j] == 1 && (x - y == i - j || x + y == i + j))
return false;
}
return true;
}
void dfs(int row)
{
if (row == n + 1)
{
cnt++;
print();
return;
}
for(int j=1;j<=n;j++)
if (check(row,j))
{
f[row][j] = 1;
dfs(row + 1);
f[row][j] = 0;
}
}
int main()
{
cin >> n;
dfs(1);
cout << cnt<<endl;
}
3.BFS->奇怪的电梯
问题描述:有一天桐桐做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1≤i≤N)上有一个数字K;(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5代表了Ki (K1=3,K2=3,…),从一楼开始。在一楼,按“上,”可以到4楼,按“下”是不起作用的,因为没有-2楼。那么,从A楼到B楼至少要按几次按钮呢?
对于BFS,我们可以借助先进先出的队列来完成。
代码:
#include<iostream>
#include<queue>
//BFS算法 奇怪的电梯
using namespace std;
bool visited[205];//记录是否已经到过这层,最短路径问题,到走过的楼层无意义
struct node//楼层节点
{
int now;//当前层数
int count;//当前启用电梯次数
};
queue<node>Q;//用来保存当前楼层节点,先进先出
int kk[205];//第i层上的number
int main()
{
int n, a, b;
cin >> n >> a >> b;
for (int i = 1; i <=n; i++)
cin >> kk[i];
Q.push(node{ a, 0 });//入队
while (not Q.empty())
{
node u = Q.front();//提取队首元素
Q.pop();//弹出队首元素
if (u.now == b)//是目标楼层,结束
{
cout << u.count;
return 0;
}
int df = u.now + kk[u.now];//上楼
if (df <= n && not visited[df])//是否能走
{
visited[df] = true;
Q.push(node{ df,u.count + 1 });
}
df = u.now - kk[u.now];//下楼
if (df >= 1 && not visited[df])//是否能走
{
visited[df] = true;
Q.push(node{ df,u.count + 1 });
}
}
cout << "-1";
return 0;
}