关于广度优先搜索(BFS)的几个问题

BFS搜索主要用队列的数据结构。

1.数字操作

ccfffcd9ab1b475f9ed2ae45e94a904b.png

1a26d0c7616e48b7b6a154f399143158.jpeg

画了一个图来方便梳理理解过程

整体思路

  1. 初始化:从整数1开始,将其加入队列。

  2. BFS遍历:每次从队列中取出一个数,检查是否等于目标数n。如果等于,则返回当前步数。

  3. 扩展节点:如果不等于,则将当前数加1和乘2的结果(如果不超过n)加入队列,并标记这些数已访问,避免重复处理。

  4. 步数增加:每次处理完一层节点后,步数加1

 

时空复杂度

  • 时间复杂度:在最坏情况下,每个数最多被访问一次,时间复杂度为O(n)。

  • 空间复杂度:需要一个队列来存储当前层的所有数,以及一个数组来标记已访问的数,空间复杂度为O(n)。

 

代码

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<queue>
using namespace std;

const int MAXN = 100000;
bool inQueue[MAXN + 1] = { false };

int getStep(int n) {
	int step = 0;
	queue<int> q;
	q.push(1);
	while (true)
	{
		int cnt = q.size();
		for (int i = 0; i < cnt; i++)
		{
			int front = q.front();
			q.pop();
			
			if (front == n)
			{
				return step;
			}

			inQueue[front] = true;

			if (front * 2 <= n && !inQueue[front * 2]) 
			{
				inQueue[front * 2] = true;
				q.push(front * 2);
			}

			if (front + 1 <= n && !inQueue[front + 1]) 
			{
				inQueue[front +1] = true;
				q.push(front + 1);
			}
		}
		step++;
	}
}

int main()
{
	int n, step = 0;
	scanf("%d", &n);
	printf("%d", getStep(n));
	return 0;
}

核心代码:

inQueue[front] = true;

if (front * 2 <= n && !inQueue[front * 2])
{
				inQueue[front * 2] = true;
				q.push(front * 2);
}

if (front + 1 <= n && !inQueue[front + 1])
{
				inQueue[front + 1] = true;
				q.push(front + 1);
}

step++;

运行时我对核心代码进行了改进,即在对数字进行 *2 / +1 操作前对数字是否已经进行过相关操作进行判断。比如第一次产生了两个2,其实第二个2完全没有必要再进行*2 / +1 操作,因为对比左边数字的树,我们可以发现这是重复操作,所以我把代码改成了(即增加了if(inQueue[front]==false)这一判断条件):

if (inQueue[front] == false)
{
	inQueue[front] = true;

	if (front * 2 <= n && !inQueue[front * 2])
	{
		inQueue[front * 2] = true;
		q.push(front * 2);
	}

	if (front + 1 <= n && !inQueue[front + 1])
	{
		inQueue[front + 1] = true;
		q.push(front + 1);
	}
}
step++;

但最后的结果是,没有增加 if 条件判断的代码   运行时长比    添加的代码  要短,我思考不出结果,欢迎大家一起讨论

0526c58560134f93ae97486a8c8740e1.png

 

 

2.矩阵中的块

7e868c2a6a4b487e97fb914165247770.png

8995ccc8f1664a739224e01ce5837b0d.png

可以与上下左右四个方位构成“块”,单纯对角线构不成块

整体思路

  1. 初始化矩阵和辅助数据结构

    • 读取输入矩阵的大小nm,并初始化矩阵matrix

    • 创建一个布尔数组inQueue,用于标记矩阵中的某个位置是否已经被访问过。

  2. 遍历矩阵

    • 使用双重循环遍历矩阵中的每一个元素。

    • 如果当前元素是1且未被访问过,则从这个元素开始进行BFS。

  3. BFS过程

    • 创建一个队列q,用于存储待访问的位置。

    • 将当前位置(x, y)加入队列,并标记为已访问。

    • 不断从队列中取出元素,检查其上下左右四个相邻位置。

    • 如果相邻位置是1且未被访问过,则将其加入队列并标记为已访问。

    • 访问。

  4. 统计“块”的数量

    • 每次从新的未访问过的1开始进行BFS时,计数器加一。

    • 最终计数器的值即为矩阵中“块”的数量。

 

时空复杂度

  • 时间复杂度:O(n * m),其中n是矩阵的行数,m是矩阵的列数。每个位置最多被访问一次。

  • 空间复杂度:O(n * m),用于存储矩阵和辅助数据结构inQueue

 

 代码

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>

#include <queue>

#include <utility>

using namespace std;



typedef pair<int, int> Position;



const int MAXN = 100;

int n, m, matrix[MAXN][MAXN];

bool inQueue[MAXN][MAXN] = { false };



const int MAXD = 4;

int dx[MAXD] = { 0, 0, 1, -1 };

int dy[MAXD] = { 1, -1, 0, 0 };



bool canVisit(int x, int y) 
{

    return x >= 0 && x < n && y >= 0 && y < m && matrix[x][y] == 1 && !inQueue[x][y];

}



void BFS(int x, int y) 
{

    queue<Position> q;

    q.push(Position(x, y));

    inQueue[x][y] = true;

    while (!q.empty()) {

        Position front = q.front();

        q.pop();

        for (int i = 0; i < MAXD; i++) 
        {

            int nextX = front.first + dx[i];

            int nextY = front.second + dy[i];

            if (canVisit(nextX, nextY)) 
            {

                inQueue[nextX][nextY] = true;

                q.push(Position(nextX, nextY));

            }

        }

    }

}



int main() {

    scanf("%d%d", &n, &m);

    for (int i = 0; i < n; i++) 
    {

        for (int j = 0; j < m; j++) 
        {

            scanf("%d", &matrix[i][j]);

        }

    }

    int counter = 0;

    for (int i = 0; i < n; i++) 
    {

        for (int j = 0; j < m; j++) 
        {

            if (matrix[i][j] == 1 && !inQueue[i][j]) 
            {

                BFS(i, j);

                counter++;

            }

        }

    }

    printf("%d", counter);

    return 0;

}

 

 

3.迷宫问题(最小步数)

c4ade23af1c44300a7192178c83e8ab8.png

4afbd3625b2d40e2b09d5cd01bb23f4d.png

 广度优先搜索(BFS)是一种图搜索算法,适用于在无权图中寻找最短路径

在本题中,迷宫可以看作一个无权图,其中每个格子是一个节点,相邻的平地格子之间有边相连。

BFS通过逐层扩展的方式,确保找到的路径是最短的

 

整体思路

  1. 初始化:从迷宫的左上角(起点)开始,将起点加入队列,并标记为已访问。

  2. 逐层扩展:使用队列进行BFS,每次从队列中取出一个节点,检查其是否为终点。如果是终点,则返回当前步数。

  3. 邻居节点处理:对于当前节点的每个合法邻居节点(即上下左右四个方向的平地格子),将其加入队列,并标记为已访问。

  4. 步数更新:每处理完一层节点,步数加一。

  5. 终止条件:如果队列为空且未找到终点,则返回-1,表示无法到达终点。

时空复杂度

  • 时间复杂度:O(n * m),其中n和m分别是迷宫的行数和列数。每个节点最多被访问一次。

  • 空间复杂度:O(n * m),用于存储迷宫信息和访问标记。

代码

#include <cstdio>

#include <queue>

#include <utility>

using namespace std;



typedef pair<int, int> Position;



const int MAXN = 100;

int n, m, maze[MAXN][MAXN];

bool inQueue[MAXN][MAXN] = { false };



const int MAXD = 4;

int dx[MAXD] = { 0, 0, 1, -1 };

int dy[MAXD] = { 1, -1, 0, 0 };



bool canVisit(int x, int y) {

    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !inQueue[x][y];

}



int BFS(int x, int y) 
{

    queue<Position> q;

    q.push(Position(x, y));

    inQueue[x][y] = true;

    int step = 0;

    while (!q.empty()) 
    {

        int cnt = q.size();//每一层需要探索的结点个数

        while (cnt--) 
        {

            Position front = q.front();

            q.pop();

            if (front.first == n - 1 && front.second == m - 1) {

                return step;

            }

            for (int i = 0; i < MAXD; i++) {

                int nextX = front.first + dx[i];

                int nextY = front.second + dy[i];

                if (canVisit(nextX, nextY)) {

                    inQueue[nextX][nextY] = true;

                    q.push(Position(nextX, nextY));

                }

            }

        }

        step++;//探索完一层后步数加一

    }

    return -1;

}



int main() {

    scanf("%d%d", &n, &m);

    for (int i = 0; i < n; i++) {

        for (int j = 0; j < m; j++) {

            scanf("%d", &maze[i][j]);

        }

    }

    int step = BFS(0, 0);

    printf("%d", step);

    return 0;

}

 本题中BFS核心代码(逐层搜索):

while (!q.empty())      //
    {

        int cnt = q.size();//每一层需要探索的结点个数

        while (cnt--) //逐层搜索的关键
        {

            Position front = q.front();

            q.pop();

            if (front.first == n - 1 && front.second == m - 1) {

                return step;

            }

            for (int i = 0; i < MAXD; i++) {

                int nextX = front.first + dx[i];

                int nextY = front.second + dy[i];

                if (canVisit(nextX, nextY)) {

                    inQueue[nextX][nextY] = true;

                    q.push(Position(nextX, nextY));//实现广度搜索

                }

            }

        }

        step++;//探索完一层后步数加一

    }

之前的文章  深度优先搜索(DFS)的几个问题  中关于DFS的核心代码(递归回溯):

for (int i = 0; i < MAXD; i++)        //依据下→上→右→左的顺序依次遍历,

{
        int nextX = x + dx[i];
        int nextY = y + dy[i];
        if (isValid(nextX, nextY))    //如果isValid判断无效则再次进入for循环换一个方向遍历

        {
            DFS(nextX, nextY, step + 1);//实现深度搜索
        }
}

 

4.迷宫最短路径

b8a483cca62c4026a607d6dd9dc43314.png 8f92c802ce7a409a89cb5f5661258668.png

 DFS最短路径需要不断比较得到的可能路径步数,然后用新的最短路径替代旧的最短路径。路径可以用vector实现(即)。BFS的路径存储可考虑记录前驱,然后回溯

整体思路

  1. 初始化:首先,我们需要读取迷宫的尺寸和布局,并初始化一些必要的变量和数据结构,如队列、访问标记数组和前驱数组。
  2. BFS搜索:从起点(左上角)开始,使用BFS逐步探索所有可能的路径。每次移动时,检查四个方向(上、下、左、右),并将合法的移动位置加入队列。
  3. 记录路径:在搜索过程中,记录每个位置的前驱位置,以便在找到终点后能够回溯出完整的路径。
  4. 输出路径:一旦到达终点(右下角),通过前驱数组回溯路径并输出。

时空复杂度

  • 时间复杂度:在最坏情况下,BFS需要遍历迷宫中的每一个位置,因此时间复杂度为O(n×m),其中n和m分别是迷宫的行数和列数。
  • 空间复杂度:需要存储迷宫、访问标记、前驱数组和队列,因此空间复杂度也是O(n×m)。

代码 

#include <cstdio>
#include <queue>
#include <utility>
#include <algorithm>
using namespace std;

typedef pair<int, int> Position;

const int MAXN = 100;
int n, m, maze[MAXN][MAXN];
bool inQueue[MAXN][MAXN] = {false};
Position pre[MAXN][MAXN];

const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};

bool canVisit(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !inQueue[x][y];
}

void BFS(int x, int y) {
    queue<Position> q;
    q.push(Position(x, y));
    inQueue[x][y] = true;
    while (!q.empty()) {
        Position front = q.front();
        q.pop();
        if (front.first == n - 1 && front.second == m - 1) {
            return;
        }
        for (int i = 0; i < MAXD; i++) {
            int nextX = front.first + dx[i];
            int nextY = front.second + dy[i];
            if (canVisit(nextX, nextY)) {
                pre[nextX][nextY] = Position(front.first, front.second);
                inQueue[nextX][nextY] = true;
                q.push(Position(nextX, nextY));
            }
        }
    }
}

void printPath(Position p) {
    Position prePosition = pre[p.first][p.second];
    if (prePosition == Position(-1, -1)) {
        printf("%d %d\n", p.first + 1, p.second + 1);
        return;
    }
    printPath(prePosition);
    printf("%d %d\n", p.first + 1, p.second + 1);
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }
    fill(pre[0], pre[0] + n * m, Position(-1, -1));
    BFS(0, 0);
    printPath(Position(n - 1, m - 1));
    return 0;
}

本题的关键是以下代码:

void printPath(Position p) {
    Position prePosition = pre[p.first][p.second];
    if (prePosition == Position(-1, -1)) {
        printf("%d %d\n", p.first + 1, p.second + 1);
        return;
    }
    printPath(prePosition);
    printf("%d %d\n", p.first + 1, p.second + 1);
}

根据题目的输入案例,画图理解如下:

 e010c22f39f6481394c6acad6d5fa1f4.jpeg

 

5.跨步迷宫

015d3249f7184e5ab65ad0a63ba42a9e.png

586f0cfe4afd44619c4f5b3115373aea.png

这道题的关键点在于移动两格时,移动合法条件如何设置。 

我们可以根据题目中关于移动两格的限制条件设置:且只能移动到平地上(不允许跨越墙壁)

代码

#include <cstdio>
#include <queue>
#include <utility>
using namespace std;

typedef pair<int, int> Position;

const int MAXN = 100;
int n, m, maze[MAXN][MAXN];
bool inQueue[MAXN][MAXN] = { false };

const int MAXD = 8;
int dx[MAXD] = { 0,  0, 0,  0, 1, -1, 2, -2 };
int dy[MAXD] = { 1, -1, 2, -2, 0,  0, 0,  0 };

bool canVisit(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !inQueue[x][y];
}

int BFS(int x, int y) {
    queue<Position> q;
    q.push(Position(x, y));
    inQueue[x][y] = true;
    int step = 0;
    while (!q.empty())
    {
        int cnt = q.size();
        while (cnt--)
        {
            Position front = q.front();
            q.pop();
            if (front.first == n - 1 && front.second == m - 1) {
                return step;
            }
            for (int i = 0; i < MAXD; i++) {
                int nextX = front.first + dx[i];
                int nextY = front.second + dy[i];
                int nextHalfX = front.first + dx[i] / 2;
                int nextHalfY = front.second + dy[i] / 2;
                if (canVisit(nextX, nextY)&&maze[nextHalfX][nextHalfY]==0) {
                    inQueue[nextX][nextY] = true;
                    q.push(Position(nextX, nextY));
                }
            }
        }
        step++;
    }
    return -1;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }
    int step=BFS(0, 0);
    printf("%d", step);
    return 0;
}

关键代码如下:

const int MAXD = 8;
int dx[MAXD] = { 0,  0, 0,  0, 1, -1, 2, -2 };
int dy[MAXD] = { 1, -1, 2, -2, 0,  0, 0,  0 };

.......

for (int i = 0; i < MAXD; i++) 
{
    int nextX = front.first + dx[i];
    int nextY = front.second + dy[i];
    int nextHalfX = front.first + dx[i] / 2;
    int nextHalfY = front.second + dy[i] / 2;
    if (canVisit(nextX, nextY)&&maze[nextHalfX][nextHalfY]==0) {
        inQueue[nextX][nextY] = true;
        q.push(Position(nextX, nextY));
    }
}

 

6. 字符迷宫

22e3b8eab848414fbf50c36c460f3b23.png

70fe82dbf8474e9583b9ce9ff2bc2536.png

这道题有两处亮点:

 ①输入的是字符。

为了减少工作量,可以继续使用之前的函数,但是要对输入的字符进行处理

②起点终点不再固定。

对输入的起点和终点进行保存,再传入函数。

代码

#include <cstdio>
#include <queue>
#include <utility>
using namespace std;

typedef pair<int, int> Position;

const int MAXN = 100;
int n, m, maze[MAXN][MAXN];
bool inQueue[MAXN][MAXN] = { false };

const int MAXD = 4;
int dx[MAXD] = { 0,  0, 1, -1};
int dy[MAXD] = { 1, -1, 0, 0 };

bool canVisit(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !inQueue[x][y];
}

int BFS(Position start,Position target) {
    queue<Position> q;
    q.push(start);
    inQueue[start.first][start.second] = true;
    int step = 0;
    while (!q.empty())
    {
        int cnt = q.size();
        while (cnt--)
        {
            Position front = q.front();
            q.pop();
            if (front==target) {
                return step;
            }
            for (int i = 0; i < MAXD; i++) 
            {
                int nextX = front.first + dx[i];
                int nextY = front.second + dy[i];
      
                if (canVisit(nextX, nextY)) {
                    inQueue[nextX][nextY] = true;
                    q.push(Position(nextX, nextY));
                }
            }
        }
        step++;
    }
    return -1;
}

int main() {
    Position start, target;
    char c;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) 
    {
        getchar();
        for (int j = 0; j < m; j++) 
        {
            scanf("%c", &c);
            if (c == '.')
                maze[i][j] = 0;
            else if (c == '*')
                maze[i][j] = 1;
            else if (c == 'S')
                start = Position(i, j);
            else if (c == 'T')
                target = Position(i, j);
        }
    }
    int step = BFS(start, target);
    printf("%d", step);
    return 0;
}

 

7.多终点迷宫问题

04e8c664257647129080979d3da93c6e.png

这道题没有什么特别的,就是在每到达一个之前没到达的点时要注意把此时对应的步数存储好

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
#include<algorithm>
using namespace std;

typedef pair<int, int> Position;

const int INF = 0x3f;
const int MAXN = 100;
int n, m, maze[MAXN][MAXN];
bool inQueue[MAXN][MAXN] = { false };
int minStep[MAXN][MAXN];

const int MAXD = 4;
int dx[MAXD] = { 0,  0, 1, -1};
int dy[MAXD] = { 1, -1, 0, 0 };

bool canVisit(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !inQueue[x][y];
}

void BFS(int x,int y) {
    memset(minStep, -1, sizeof(minStep));
    queue<Position> q;
    q.push(Position(x,y));
    inQueue[x][y] = true;
    minStep[x][y] = 0;
    int step = 0;
    while (!q.empty())
    {
        int cnt = q.size();
        while (cnt--)
        {
            Position front = q.front();
            q.pop();
        
            for (int i = 0; i < MAXD; i++) 
            {
                int nextX = front.first + dx[i];
                int nextY = front.second + dy[i];
                if (canVisit(nextX, nextY)) {
                    inQueue[nextX][nextY] = true;
                    minStep[nextX][nextY] = step + 1;
                    q.push(Position(nextX, nextY));
                }
            }
        }
        step++;
    }
}

int main() {
   
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) 
    {
        for (int j = 0; j < m; j++) 
        {
            scanf("%d", &maze[i][j]);
        }
    }
    BFS(0, 0);

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            printf("%d", minStep[i][j]);
            printf(j < m - 1 ? " " : "\n");
        }
    }

    return 0;
}

 

8. 迷宫问题-传送点

9d399ba5ee17499aa9768f6a33c38b3c.png

12ecbeca92cf4f68a82f3630c6b900b4.png

这道题比较特殊的点在于如何处理这个传送关系,BFS的“地毯式”搜索可以让我们不用考虑“是否传送”,遇到传送点把它放进路径队列里就可以了。

传送点怎么处理可以考虑用map函数形成映射关系。 

代码

#include <cstdio>
#include <queue>
#include <utility>
#include <map>
using namespace std;

typedef pair<int, int> Position;

const int MAXN = 100;
int n, m, maze[MAXN][MAXN];
bool inQueue[MAXN][MAXN] = { false };
map<Position, Position> transMap;

const int MAXD = 4;
int dx[MAXD] = { 0,  0, 1, -1};
int dy[MAXD] = { 1, -1, 0, 0 };

bool canVisit(int x, int y) 
{
    return x >= 0 && x < n && y >= 0 && y < m &&(maze[x][y] == 0 || maze[x][y] == 2) && !inQueue[x][y];
}

int BFS(int x,int y) 
{
    queue<Position> q;
    q.push(Position(x,y));
    inQueue[x][y] = true;

    int step = 0;
    while (!q.empty())
    {
        int cnt = q.size();

        while (cnt--)
        {
            Position front = q.front();
            q.pop();

            if (front.first == n - 1 && front.second==m-1) 
            {
                return step;
            }
        
            for (int i = 0; i < MAXD; i++) 
            {
                int nextX = front.first + dx[i];
                int nextY = front.second + dy[i];

                if (canVisit(nextX, nextY)) 
                {
                    inQueue[nextX][nextY] = true;
                    q.push(Position(nextX, nextY));

                    if (maze[nextX][nextY] == 2) 
                    {
                        Position transPosition = transMap[Position(nextX, nextY)];
                        inQueue[transPosition.first][transPosition.second] = true;
                        q.push(transPosition);
                    }
                }
            }
        }
        step++;
    }

    return -1;
}

int main() {
   
    vector<Position> transVector;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) 
    {
        for (int j = 0; j < m; j++) 
        {
            scanf("%d", &maze[i][j]);
            if (maze[i][j] == 2) {
                transVector.push_back(Position(i, j));
            }
        }
    }

    transMap[transVector[0]] = transVector[1];
    transMap[transVector[1]] = transVector[0];

    int step=BFS(0, 0);

    printf("%d", step);

    return 0;
}

关键代码:

map<Position, Position> transMap;

......

if (canVisit(nextX, nextY)) 
{
    inQueue[nextX][nextY] = true;
    q.push(Position(nextX, nextY));

    if (maze[nextX][nextY] == 2) 
    {
        Position transPosition = transMap[Position(nextX, nextY)];
        inQueue[transPosition.first][transPosition.second] = true;
        q.push(transPosition);
    }
}

......

int main()

{
    vector<Position> transVector;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) 
    {
        for (int j = 0; j < m; j++) 
        {
            scanf("%d", &maze[i][j]);
            if (maze[i][j] == 2) {
                transVector.push_back(Position(i, j));
            }
        }
    }

    transMap[transVector[0]] = transVector[1];
    transMap[transVector[1]] = transVector[0];
......

}

 

 9.中国象棋-马-无障碍

5978dc3810d64442b73b2e0472b23f39.png

874952d7aa324673b737b4f58a5129d1.png

 

“马踏棋盘”与7.多终点迷宫问题相似,差别在于移动位置的设置(可参考5.跨步迷宫

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
#include<algorithm>
using namespace std;

typedef pair<int, int> Position;

const int MAXN = 100;
int n, m;
bool inQueue[MAXN][MAXN] = { false };
int minStep[MAXN][MAXN];

const int MAXD = 8;
int dx[MAXD] = { -2, -1, 1, 2, -2, -1, 1, 2 };
int dy[MAXD] = { 1, 2, 2, 1, -1, -2, -2, -1 };

bool canVisit(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && !inQueue[x][y];
}

void BFS(int x, int y) {
    memset(minStep, -1, sizeof(minStep));
    queue<Position> q;
    q.push(Position(x, y));
    inQueue[x][y] = true;
    minStep[x][y] = 0;
    int step = 0;

    while (!q.empty())
    {
        int cnt = q.size();
        while (cnt--)
        {
            Position front = q.front();
            q.pop();

            for (int i = 0; i < MAXD; i++)
            {
                int nextX = front.first + dx[i];
                int nextY = front.second + dy[i];
                if (canVisit(nextX, nextY)) {
                    inQueue[nextX][nextY] = true;
                    minStep[nextX][nextY] = step + 1;
                    q.push(Position(nextX, nextY));
                }
            }
        }
        step++;
    }
}

int main() {

    int x, y;
    scanf("%d%d%d%d", &n, &m, &x, &y);

    BFS(x-1,y-1);

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            printf("%d", minStep[i][j]);
            printf(j < m - 1 ? " " : "\n");
        }
    }

    return 0;
}

 

10.中国象棋-马-有障碍

0b2d85adf2e845b5b3fbad7ea87ffa59.png

18c170cf57d44b078038c11a18d005b7.png

e16c4d90a78544bb901dab0c442d4ad7.png

“马踏棋盘”与7.多终点迷宫问题相似,差别在于移动位置的设置(可参考5.跨步迷宫),比9.多了障碍设置,可以增加移动条件。

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
#include <map>
using namespace std;

typedef pair<int, int> Position;

const int MAXN = 100;
int n, m;
bool inQueue[MAXN][MAXN] = { false };
int minStep[MAXN][MAXN];
map<Position, bool> isBlock;

const int MAXD = 8;
int dx[MAXD] = { -2, -1, 1, 2, -2, -1, 1, 2 };
int dy[MAXD] = { 1, 2, 2, 1, -1, -2, -2, -1 };

bool canVisit(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m && !inQueue[x][y] && !isBlock[Position(x, y)];
}

void BFS(int x, int y) {
    memset(minStep, -1, sizeof(minStep));
    queue<Position> q;
    q.push(Position(x, y));
    inQueue[x][y] = true;
    minStep[x][y] = 0;
    int step = 0;

    while (!q.empty())
    {
        int cnt = q.size();
        while (cnt--)
        {
            Position front = q.front();
            q.pop();

            for (int i = 0; i < MAXD; i++)
            {
                int nextX = front.first + dx[i];
                int nextY = front.second + dy[i];
                if (canVisit(nextX, nextY)&&!isBlock[Position(front.first+dx[i]/2,front.second+dy[i]/2)])
                {
                    inQueue[nextX][nextY] = true;
                    minStep[nextX][nextY] = step + 1;
                    q.push(Position(nextX, nextY));
                }
            }
        }
        step++;
    }
}

int main() {

    int x, y;
    scanf("%d%d%d%d", &n, &m, &x, &y);

    int k, blockX, blockY;
    scanf("%d", &k);
    for (int i = 0; i < k; i++)
    {
        scanf("%d%d", &blockX, &blockY);
        isBlock[Position(blockX - 1, blockY - 1)] = true;
    }

    BFS(x-1,y-1);

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            printf("%d", minStep[i][j]);
            printf(j < m - 1 ? " " : "\n");
        }
    }

    return 0;
}

bool类型的默认初始化值是false。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值