173. 矩阵距离(多源点的最短路径问题)

给定一个N行M列的01矩阵A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:

dist(A[i][j],A[k][l])=|i−k|+|j−l|
输出一个N行M列的整数矩阵B,其中:

B[i][j]=min1≤x≤N,1≤y≤M,A[x][y]=1dist(A[i][j],A[x][y])
输入格式
第一行两个整数n,m。

接下来一个N行M列的01矩阵,数字之间没有空格。

输出格式
一个N行M列的矩阵B,相邻两个整数之间用一个空格隔开。

数据范围
1≤N,M≤1000
输入样例:

3 4
0001
0011
0110

输出样例:

3 2 1 0
2 1 0 0
1 0 0 1

代码

#include 
#include
#include
using namespace std;

int n,m,dx[5]={-1,0,1,0},dy[5]={0,1,0,-1};//上右下左四个点的偏移量
char A[1005][1005];
int B[1005][1005];

void bfs(){
    memset(B,-1,sizeof B);//初始化B矩阵为-1,代表所有点均未被访问
    queue<pair<int,int> > q;//定义队列实现广搜
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(A[i][j]=='1'){//矩阵A中所有为1的点为起点
                q.push({i,j});//将其下标压入队列
                该点离某起点的最短距离为0(自己就是起点之一)
                B[i][j]=0;//,标志该点已被访问
            }
        }
    }//队列中的点离某起点(A矩阵中值为1的点)的最短距离是单调递增
    while(q.size()){
        auto f = q.front();//取出队头
        q.pop();//弹出队头
        int x = f.first;//获取队头横坐标
        int y = f.second;//获取队头纵坐标
        for(int i=0;i<4;i++){//遍历队头直接连接的四个方向的点
            int a = x + dx[i];//获得其坐标
            int b = y + dy[i];
            if(a>=0&&a<n&&b>=0&&b<m&&B[a][b]==-1){//该点未越界且未访问过
                //该点离某个起点的最短距离等于队头元素离起点的最短距离+1
                B[a][b]=B[x][y]+1;
                q.push({a,b});//将该点下标压入队列
            }
        }
    }
}

int main()
{
    cin >> n>> m;
    for(int i=0;i<n;i++)//因为是01字符串所以可以一次输1行
        cin>>A[i];
    //广搜:多源点最短路径问题,也可以把他看作单源点最短路径问题,引入一个虚拟结点
    bfs();//虚拟结点到各个起点的距离为0
    for(int i=0;i<n;i++){//输出其结果
        for(int j=0;j<m;j++){
            cout<<B[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

你可能感兴趣的:(算法笔试面试常考题)