基础搜索
基础搜索
深度优先搜索(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;
}
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号