二维矩阵最短路径 :广度优先搜索

本文介绍了一个寻找地图上从任意传送点到唯一任务点最短路径的算法问题。提供了Java和C++两种语言的实现方案,并详细解释了如何利用广度优先搜索(BFS)算法来解决该问题。

题目:

要去一个任务点(任务点用字符”T“ 表示)完成任务, 地图上多个传送点(传送点用字符"X" 表示)。可以选择任意一个传送点作为起点, 请问哪些传送点到任务点的距离最短。

在地图上只能上下左右移动,不能斜着移动。

输入描述:

第一行包含2个整数N和M, 接下来N行每行包含M个字符, 字符”T“表示任务点(只有一个), 字符”X“表示传送点,字符”0“表示可以通行的路, 字符”1“表示不可以通行的障碍物。

输出描述:

输出两行,第一行包含一个整数,表示传送点到任务点的最短距离,第二行包含到任务点距离最短的所有传送点的坐标(先行后列,都是从0开始计数),有多个坐标时按照字典序排列(行号小的排在前面, 行号一样的列号小的排在前面)。

不能到达只输出一行0.

解决方案:

(1)java实现

package com.freewolf.byteDance;

import java.util.*;

/**
 * @author fgs
 * @since 2020/9/26 19:13
 */
public class pingduoduo2 {
    private static int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    private static int row;
    private static int col;

    public static char[][] deepCopy(char[][] grid){
        char[][] mask = new char[grid.length][grid[0].length];
        for(int i = 0; i < grid.length; ++i){
            for (int j = 0; j < grid[0].length; j++) {
                mask[i][j] = grid[i][j];
            }
        }
        return mask;
    }

    public static int shortestPath(char[][] grid, int c, int l){
        Queue<int[]> pos = new LinkedList<>();
        int[][] length = new int[row][col];
        length[c][l] = 1; // 直接用grid[i][j]记录从起点到这个点的最短路径长。按照题意 起点也有长度1
        pos.add(new int[]{c,l});
        int[] xy = new int[2];
        while(!pos.isEmpty()){ // 求最短路径 使用BFS
            xy = pos.remove();
            if(grid[xy[0]][xy[1]] == 'T') break;
            if(grid[xy[0]][xy[1]] == '1') continue; // 无法通行
            if(grid[xy[0]][xy[1]] == 'X' && (c != xy[0] && l != xy[1])) continue; // X 不能通行
            int preLength = length[xy[0]][xy[1]]; // 当前点的路径长度
            for(int i = 0; i < 4; i++){ // 共有四个方向
                int newX = xy[0] + directions[i][0];
                int newY = xy[1] + directions[i][1];
                if(inGrid(newX, newY) && length[newX][newY] == 0){
                    pos.add(new int[]{newX, newY});
                    length[newX][newY] = preLength + 1; // 下一个点的路径长度要+1
                }
            }
        }
        return grid[xy[0]][xy[1]] != 'T'? Integer.MAX_VALUE: length[xy[0]][xy[1]]; // 如果最后终点的值还是0,说明没有到达
    }

    private static boolean inGrid(int x, int y){
        return x >= 0 && x < row && y >= 0 && y < col;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int M = sc.nextInt();
        row = N;
        col = M;
        Map<Integer, Integer> point = new HashMap<Integer, Integer>();
        char[][] grid = new char[N][M];
        for(int i = 0; i < N; ++i){
            String tmp = sc.next();
            char[] chars = tmp.toCharArray();
            for(int j = 0; j < M; ++j){
                if(chars[j] == 'X'){
                    point.put(i, j);
                }
            }
            grid[i] = chars;
        }

        int minLen = Integer.MAX_VALUE;
        Map<Integer, Integer> ret = new TreeMap<>();
        for(Map.Entry<Integer, Integer> entry: point.entrySet()){
            int x = entry.getKey();
            int y = entry.getValue();
            int len = shortestPath(grid, x, y);
            if(len == minLen) ret.put(x, y);
            else if(len < minLen) {
                ret.clear();
                ret.put(x, y);
                minLen = len;
            }
        }
        if(minLen == Integer.MAX_VALUE) {
            System.out.println(-1);
            return;
        }
        System.out.println(minLen - 1);
        for(Map.Entry<Integer, Integer> entry : ret.entrySet()){
            System.out.print(entry.getKey() + " " + entry.getValue() + " ");
        }
        System.out.println();
    }
}

/*
5 6
X00100
00000X
01T000
0X1010
00000X
 */

(2)C++实现:

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
static int N, M;
static int directions[4][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };

bool inGrid(int newX, int newY) {
	return newX >= 0 && newX < N && newY >= 0 && newY < M; 
}

int bfs(vector<vector<char>> &grid, int row, int col) {
	queue<pair<int, int>> pos;
	pos.push(make_pair(row, col));
	vector<vector<int>> length(grid.size(), vector<int>(grid[0].size(), 0));
	length[row][col] = 1;
	pair<int, int> xy;
	while (!pos.empty()) {
		xy = pos.front();
		pos.pop();
		if (grid[xy.first][xy.second] == 'T') break;
		if (grid[xy.first][xy.second] == 'X' && (xy.first != row && xy.second != col)) continue;
		int preLength = length[xy.first][xy.second];
		for (int i = 0; i < 4; ++i) {
			int newX = xy.first + directions[i][0];
			int newY = xy.second + directions[i][1];
			if (inGrid(newX, newY) && length[newX][newY] == 0 && grid[newX][newY] != '1') {
				pos.push(make_pair(newX, newY));
				length[newX][newY] = preLength + 1;
			}
		}
	}
	return grid[xy.first][xy.second] != 'T' ? INT_MAX : length[xy.first][xy.second];
}

int main()
{
	//int N = 0, M = 0;
	cin >> N >> M;
	vector<vector<char>> grid(N, vector<char>(M, -1));
	vector<pair<int, int>> points;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < M; ++j) {
			char tmp;
			cin >> tmp;
			if (tmp == 'X') points.push_back(make_pair(i, j));
			grid[i][j] = tmp;
		}
	}
	int minLen = INT_MAX;
	vector<pair<int, int>> ret;
	for (int i = 0; i < points.size(); ++i) {
		int len = bfs(grid, points[i].first, points[i].second);
		if (len == minLen) ret.push_back(points[i]);
		else if (len < minLen) {
			minLen = min(len, minLen);
			ret.clear();
			ret.push_back(points[i]);
		}		
	}
	if (minLen == INT_MAX) {
		cout << -1 << endl;
		return 0;
	}
	cout << minLen - 1 << endl;
	for (int i = 0; i < ret.size(); ++i) {
		cout << ret[i].first << " " << ret[i].second << " ";
	}
	cout << endl;
	return 0;
}

补充:

如果不需要确定当前遍历到了哪一层,模板如下:

复制代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

void bfs() {

    vis[] = 0;

    queue<int> pq(start_val);

 

    while (!pq.empty()) {

        int cur = pq.front(); pq.pop();

        for (遍历cur所有的相邻节点nex) {

            if (nex节点有效 && vis[nex]==0){

                vis[nex] = 1;

                pq.push(nex)

            }

        }

    }

}

如果需要确定遍历到哪一层,模板如下;

复制代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

void bfs() {

    int level = 0;

    vis[] = 0// or set

    queue<int> pq(original_val);

    while (!pq.empty()) {

        int sz = pq.size();

 

        while (sz--) {

                int cur = pq.front(); pq.pop();

            for (遍历cur所有的相邻节点nex) {

                if (nex节点有效 && vis[nex] == 0) {

                    vis[nex] = 1;

                    pq.push(nex)

                }

            // end for

        // end inner while

        level++;

 

    // end outer while

}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值