快去自定义签名吧~|

张詠然

园龄:3年6个月粉丝:3关注:3

基础搜索

基础搜索

深度优先搜索(dfs, 栈实现)

dfs十分简单,不搜到最后不会往回走

只需要一个例题就可以整明白dfs是怎么应用的

全排列问题

给定一个n,输出n的全排列

分析:

每增加一个数字就向下搜到一个节点

我们从第一个开始搜,直到搜到第n个数字结束

搜的过程中记录搜过了那个数字,之后就不能搜这个数字

代码实现:

#include <iostream>
using namespace std;
const int N = 10;
int n;
int val[N];
bool vis[N];
void dfs(int u)
{
if (u == n)
{
for (int i = 0; i < n; i ++ ) printf(" %d", val[i]);
printf("\n");
return;
}
for (int i = 1; i <= n; i ++ )
if (!vis[i])
{
val[u] = i;
vis[i] = true;
dfs(u + 1);
// 恢复现场
vis[i] = false;
val[u] = 0;
}
}
int main()
{
scanf("%d", &n);
dfs(0);
return 0;
}

n皇后问题

[八皇后](P1219 [USACO1.5]八皇后 Checker Challenge - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

思路:

这是一个经典的dfs题

dfs的每个节点存的是每一层的棋子放到哪

还要额外开col, dg, udg这几个数组分别来存这一列,这个对角线,反对角线是否有棋子

代码实现:

#include <iostream>
using namespace std;
const int N = 30;
int n, tot;
int e[N];
bool col[N], dg[N], udg[N];
void dfs(int u)
{
if (u == n)
{
tot ++ ;
if (tot <= 3)
{
for (int i = 0; i < n; i ++ ) printf("%d ", e[i]);
printf("\n");
}
return;
}
for (int i = 0; i < n; i ++ )
if (!col[i] && !dg[u + i] && !udg[n - u + i])
{
e[u] = i + 1;
col[i] = dg[u + i] = udg[n - u + i] = true;
dfs(u + 1);
col[i] = dg[u + i] = udg[n - u + i] = false;
}
}
int main()
{
scanf("%d", &n);
dfs(0);
printf("%d\n", tot);
return 0;
}

第二种做法:

这种方法思路简单,每一个地方可以选择选或不选,分别递归

代码:

// 时间复杂度较高,会有几个点tle
#include <iostream>
using namespace std;
const int N = 30;
int n, cnt, tot;
int e[N];
bool col[N], row[N], dg[N], udg[N];
void dfs(int x, int y, int s)
{
if (y == n) y = 0, x ++ ;
if (x == n)
{
if (s == n && cnt < 3)
{
for (int i = 0; i < n; i ++ ) printf("%d ", e[i] + 1);
printf("\n");
cnt ++ ;
}
if (s == n) tot ++ ;
return;
}
// 放棋子
if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n])
{
e[x] = y;
row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
dfs(x, y + 1, s + 1);
row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
e[x] = 0;
}
// 不放棋子
dfs(x, y + 1, s);
}
int main()
{
scanf("%d", &n);
dfs(0, 0, 0);
printf("%d", tot);
return 0;
}

宽度优先搜索(bfs, 队列实现)

宽度搜索比较沉稳,一层一层搜

因为bfs的搜索顺序,它具有最短路的性质,

如果有环的话,第一次搜到这个点的路径就是最短路

例题:

[马的遍历](P1443 马的遍历 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

bfs有一个技巧,搜下一个节点的时候不需要写很多个if

直接用一个向量来存

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 410;
int n, m, x, y;
vector<PII> q;
int d[N][N];
void bfs()
{
memset(d, -1, sizeof d);
d[x][y] = 0;
q.push_back({x, y});
int dx[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int dy[8] = {2, 1, -1, -2, 2, 1, -1, -2};
int hh = 0, tt = 0;
while (hh <= tt)
{
auto t = q[hh ++ ];
for (int i = 0; i < 8; i ++ )
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= m && d[a][b] == -1)
{
d[a][b] = d[t.first][t.second] + 1;
q.push_back({a, b});
tt ++ ;
}
}
}
}
int main()
{
scanf("%d%d%d%d", &n, &m, &x, &y);
bfs();
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= m; j ++ )
printf("%-5d", d[i][j]);
printf("\n");
}
return 0;
}

本文作者:张詠然

本文链接:https://www.cnblogs.com/zyrddd/p/16595122.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   张詠然  阅读(23)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起