【C++】数据结构之深搜+广搜 经典题型

DFS

1.排列数字

给定一个整数 n,将数字 1∼n

排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。
输入格式

共一行,包含一个整数 n。

输出格式

按字典序输出所有排列方案,每个方案占一行。

数据范围

1≤ n ≤7

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 10;
int path[N];
bool flag[N];
int n;
void dfs(int u)//深度优先搜索
{
    if(u==n) {
        for(int i=0;i<n;i++) cout<<path[i]<<" ";
        puts("");
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(!flag[i])
        {
            path[u]=i;
            flag[i]=true;
            dfs(u+1);//递归
            path[u]=0;//回溯
            flag[i]=false;//回溯
        }
    }
    
}
int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

2.n-皇后问题

n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
在这里插入图片描述

现在给定整数 n,请你输出所有的满足条件的棋子摆法。

输入格式

共一行,包含整数 n。

输出格式

每个解决方案占 n
行,每行输出一个长度为 n

的字符串,用来表示完整的棋盘状态。

其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。

每个方案输出完成后,输出一个空行。

注意:行末不能有多余空格。

输出方案的顺序任意,只要不重复且没有遗漏即可。

数据范围
1≤n≤9

4

输入样例:

.Q…
…Q
Q…
…Q.

…Q.
Q…
…Q
.Q…

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 20;
char g[N][N];
bool col[N],dg[N],udg[N];
int n;
void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++) puts(g[i]);
        puts("");
        return ;
    }
    for(int i=0;i<n;i++)
    {
         // 剪枝(对于不满足要求的点,不再继续往下搜索)  
        // udg[n - u + i],+n是为了保证下标非负
        if(!col[i] and !dg[u+i] and !udg[n-u+i])
        {
            g[u][i]='Q';
            col[i]=dg[u+i]=udg[n-u+i]=true;
            dfs(u+1);
            g[u][i]='.';//恢复现场+回溯
            col[i]=dg[u+i]=udg[n-u+i]=false;
        }
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    g[i][j]='.';
    dfs(0);
    return 0;
}

BFS

1.走迷宫

给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1

表示不可通过的墙壁。

最初,有一个人位于左上角 (1,1)

处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

请问,该人从左上角移动至右下角 (n,m)

处,至少需要移动多少次。

数据保证 (1,1)
处和 (n,m) 处的数字为 0,且一定至少存在一条通路。

输入格式

第一行包含两个整数 n和 m。

接下来 n
行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。

输出格式

输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围
1≤n,m≤100

输入样例:

5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出样例:

8

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 105;
typedef pair<int, int> PII;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int g[N][N],vis[N][N]={0};//g用来存图 vis用来存路劲
int m,n;
int bfs(int x,int y)
{
    queue<PII>q;
    q.push({x,y});
    vis[x][y]=1;
    while(!q.empty())
    {
        auto p=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int xx=p.first+dx[i],yy=p.second+dy[i];
            if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&!vis[xx][yy]&&!g[xx][yy])
            {
                vis[xx][yy]=vis[p.first][p.second]+1;
                q.push({xx,yy});
            }
        }
    }
    return vis[m][n]-1;//直接返回长度
}
int main()
{
    cin>>m>>n;
    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    cin>>g[i][j];
    cout<<bfs(1,1)<<endl;
    return 0;
}

2.求解迷宫从入口到出口的路径

求解迷宫从入口到出口的路径。输入一个迷宫,求从入口通向出口的可行路径。为简化问题,迷宫用二维数组 int maze[10][10]来存储障碍物的分布,假设迷宫的横向和纵向尺寸的大小是一样的,并由程序运行读入, 若读入迷宫大小的值是n(3<n<=10),则该迷宫横向或纵向尺寸都是n,规定迷宫最外面的一圈是障碍物,迷宫的入口是maze[1][1],出口是maze[n-2][n-2], 若maze[i][j] = 1代表该位置是障碍物,若maze[i][j] = 0代表该位置是可以行走的空位(0<=i<=n-1, 0<=j<=n-1)。求从入口maze[1][1]到出口maze[n-2][n-2]可以走通的路径。要求迷宫中只允许在水平或上下四个方向的空位上行走,走过的位置不能重复走,规定必须按向右、向下、向左、向上的顺序向前搜索试探。
如下这样一个迷宫:
在这里插入图片描述

对应的二维数组表示:
int maze[10][10]={
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,1,1},
{1,0,0,0,1,0,0,0,1,1},
{1,0,1,0,0,0,1,0,0,1},
{1,1,1,1,0,1,1,0,1,1},
{1,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}};

输入格式:

输入迷宫大小的整数n, 以及n行和n列的二维数组(数组元素1代表障碍物,0代表空位)。

输出格式:

依次输出从入口到出口可行路径每个位置的行列下标(i,j),每个位置间用“,”分隔。若没有通路,输出:NO。

输入样例1:

4
1 1 1 1
1 0 1 1
1 0 0 1
1 1 1 1

输出样例1:

(1,1)(2,1)(2,2)

输出样例2:

10
1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 1 0 1
1 0 0 1 0 0 0 1 0 1
1 0 0 0 0 1 1 0 0 1
1 0 1 1 1 0 0 0 0 1
1 0 0 0 1 0 0 0 0 1
1 0 1 0 0 0 1 0 0 1
1 0 1 1 1 0 1 1 0 1
1 1 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1

输出样例2:

(1,1)(1,2)(2,2)(3,2)(3,1)(4,1)(5,1)(5,2)(5,3)(6,3)(6,4)(6,5)(7,5)(8,5)(8,6)(8,7)(8,8)

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=100;
typedef pair<int,int> PII;
int Map[N][N],vis[N][N]={0};//存图+路径
int flag,n;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};//往4个方向走
stack<PII>s,s1;
void dfs(int x,int y)
{
  s.push({x,y});
  vis[x][y]=1;
  if(x==n-2 && y==n-2)
  {
   flag=1;
   return;
  }
  for(int i=0;i<4;i++)
  {
    int xx=x+dx[i],yy=y+dy[i];
   if(xx>=0&&xx<n&&yy>=0&&yy<n&&!vis[xx][yy]&&!Map[xx][yy])
    {
     vis[xx][yy]=1;
     dfs(xx,yy);//递归
     if(flag) return;//到出口时回溯
    }
  }
  s.pop();//走不通就出栈,往前找,回溯
}
int main()
{
   cin>>n;
  for(int i=0;i<n;i++)
   for(int j=0;j<n;j++)
     cin>>Map[i][j];
    dfs(1,1);
    //用堆栈输出或者可用递归
    if(s.empty()) cout<<"NO";
    else
    {
     while(!s.empty())
    {
    s1.push(s.top());
    s.pop();
    }
    while(!s1.empty())
    {
    cout<<'('<<s1.top().first<<','<<s1.top().second<<')';
    s1.pop();
    }
    }
   return 0;
}

小白上路!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在提供的AC代码中,有关于图的度优先索(DFS)和广度优先索(BFS)的实现方法。 在第一段代码中,是一个关于度优先索的实现。该代码通过递归的方式来实现度优先索。它使用了一个路径数组和一个标记数组来记录路径和访问状态。在每一次递归时,根据条件进行索,并在索完成后进行回溯操作。最终输出所有路径的结果。 在第二段代码中,是一个关于图的广度优先索的实现。该代码使用了一个队列来进行广度优先索。它使用了一个二维数组来表示图的状态和一个二维数组来记录访问状态。在索时,将起始点入队并标记为已访问,然后通过循环遍历队列中的元素,并根据条件进行索,并将符合条件的点入队并标记为已访问。最终返回从入口到出口的路径长度。 因此,根据提供的AC代码,可以实现图的度优先索和广度优先索算法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【C++】数据结构+广 经典](https://blog.csdn.net/weixin_64967734/article/details/124994451)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值