最短路模板

 第一行正整数N,接下来N行字符串,’.’表示可以通过,’#’表示障碍,’S’表示起点(有且仅有一个)

’E’表示出口(有且仅有一个)表示从S到E最短路径的长度,    无法到达则输出    -1 

#include <iostream>
#include<cstring>
#include<queue>
using namespace std;
int n;
int sx,sy;
int ex,ey;
char g[1001][1001];
bool vis[1001][1001];
int res=-1;
struct node{
    int x;
    int y;
    int step;
    node(int xx,int yy,int s){
        x=xx; y=yy; step=s;
    }
};
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void bfs(){
    queue<node>q;
    q.push(node(sx,sy,0));
    while(!q.empty()){
        node t=q.front();
        q.pop();
        int tx=t.x;
        int ty=t.y;
        int tstep=t.step;
        if(tx==ex&&ty==ey)res=tstep;
        vis[tx][ty]=true;
        for(int i=0;i<4;i++){
            int newx=(tx+dx[i]+n)%n;
            int newy=(ty+dy[i]+n)%n;
            if(!vis[newx][newy]&&g[newx][newy]!='#'){
                vis[newx][newy]=true;
                q.push(node(newx,newy,tstep+1));
            }

        }
    }
}
int main() {
    cin >> n;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++){
        string s;
        cin>>s;
        for(int j=0;j<n;j++){
            g[i][j]=s[j];
            if(s[j]=='S'){
                sx=i;
                sy=j;
            }else if(s[j]=='E'){
                ex=i;
                ey=j;
            }
        }
    }
    bfs();
    cout<<res;
    return 0;
}
Acwing920:最优乘车 BFS最短路 

算法题整理:bfs多源BFS问题 模板_宽度优先

多源BFS问题 模板

题目描述:有多个起点,求所有点到不同起点的最短路径。

做法:把所有起点加入队列然后用bfs来做。

简单证明:

可以在所有起点前加一个虚拟起点,这个虚拟起点到所有起点的路径长度为0。
 那么求所有点到起点的最短距离,就是求所有点到这个虚拟起点的最短距离。

由于虚拟起点到所有边到权值为0,所以可以把所有起点加到队列中去。

#define x first
#define y second
typedef pair<int,int> PII;
class Solution {
public:
    int maxDistance(vector<vector<int>>& g) {
       int n=g.size(),m=g[0].size(),INF=1e8;
       vector<vector<int>>dist(n,vector<int>(m,INF));
       queue<PII>q;
       for(int i=0;i<n;i++){
           for(int j=0;j<m;j++){
               if(g[i][j]){
                   dist[i][j]=0;
                   q.push({i,j});
               }
           }
       }
       int dx[4]={-1,0,1,0};
       int dy[4]={0,1,0,-1};
       while(q.size()){
           auto t =q.front();
           q.pop();
           for(int i=0;i<4;i++){
               int x=t.x+dx[i],y=t.y+dy[i];
               if(x>=0&&y>=0&&x<n&&y<m&&dist[x][y]==INF){
                   dist[x][y]=dist[t.x][t.y]+1;
                   q.push({x,y});
               }
           }
       }
       int res=-1;
       for(int i=0;i<n;i++){
               for(int j=0;j<m;j++){
                   if(!g[i][j]){
                       res=max(res,dist[i][j]);
                   }
               }
       }
       if(res==INF)res=-1;
       return res;
   } 
};
LeetCode1091二进制矩阵中的最短路径

给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。

二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即(0, 0))到 右下角 单元格(即(n - 1, n - 1))的路径,该路径同时满足下述要求:

路径途经的所有单元格都的值都是 0。路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。畅通路径的长度 是该路径途经的单元格总数。

算法题整理:bfs多源BFS问题 模板_i++_02

算法题整理:bfs多源BFS问题 模板_宽度优先_03

算法题整理:bfs多源BFS问题 模板_#include_04

#define x first
#define y second
typedef pair<int,int> PII;
class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& g) {
       if(g[0][0])return -1;
       int n=g.size();
       vector<vector<int>>dist(n,vector<int>(n,-1));
       dist[0][0]=1;
       queue<PII>q;
       q.push({0,0});
       int dx[]={-1,-1,-1,0,1,1,1,0};
       int dy[]={-1,0,1,1,1,0,-1,-1};
       while(q.size()){
           auto t=q.front();
           q.pop();
           for(int i=0;i<8;i++){
               int x=t.x+dx[i],y=t.y+dy[i];
               if(x>=0&&x<n&&y>=0&&y<n&&g[x][y]==0&&dist[x][y]==-1){
                   dist[x][y]=dist[t.x][t.y]+1;
                   q.push({x,y});
               }
           }
       }
       return dist[n-1][n-1];
    }
};

 数组模拟队列bfs

struct node{
   state;
   node(_state){
    state = _state;
   }
}queue[MAX_SIZE];
int head=0;
int tail=0;
//入队
node t=node(state);
queue[tail++]=t;
//出队
node t=queue[head++];
//判不空
while(head<tail){}

 bfs求最小操作数

算法题整理:bfs多源BFS问题 模板_图论_05

野人与传教士渡河:

N名传教士和N个野蛮人同在一个小河渡口,渡口上只有一条可容M人的小船。
问题的目标是要用这条小船把这2*N个人全部渡到对岸去,条件是在渡河的过程中,河两岸随时都保持传教士人数不少于野蛮人的人数。否则野蛮人会把处于少数的传教士吃掉。如果顺利渡河,返回最小渡河次数,否则返回-1。

算法题整理:bfs多源BFS问题 模板_图论_06

(1)河两岸都需要保持这个条件。

(2)渡船的时候也需要保持这个条件。

(3)假设从右岸为终点)可以从右岸载人渡到左岸,也算一次。

为了防止重复渡河,需要有个状态判断是否重复。

未完待续。

算法题整理:bfs多源BFS问题 模板_算法_07

TANK: 

N*M的矩阵,有坦克A和B,终点C和D 坦克A需要走到C,坦克B需要走到D。 每经过一秒,坦克可以选择周围的8个方向任意移动一步,也可以选择原地不动。 但是两个坦克不能相邻(周围8个方向),也不能去有墙的地方 问,最少需要多少秒,才能使两个坦克都达到目的地。

状态:

x1,y1,x2,y2。O(N*N)。

优化:首先判断起点和终点是否在一个集合中(dfs)(O(N*N)),如果不在的话,就直接返回。

#include<iostream>
#include<cstring>
using namespace std;
bool visit[9][9][9][9];
int sx1,sy1,sx2,sy2,ex1,ey1,ex2,ey2;
int res;
int g[9][9];
struct node{
    int x1;int y1;int x2;int y2;
    int step;
}queue[100000];
int dx[9] = {0,-1,-1,-1,0,1,1,1,0};
int dy[9] = {-1,-1,0,1,1,1,0,-1,0};
int head=0;
int tail=0;
int bfs()
{
    int x1,x2,y1,y2;
    queue[tail].x1=sx1;
    queue[tail].y1=sy1;
    queue[tail].x2=sx2;
    queue[tail].y2=sy2;
    queue[tail++].step=0;
    visit[sx1][sy1][sx2][sy2]=1;
    while(head<tail)
    {
        node t = queue[head++];
        if(t.x1==ex1&&t.y1==ey1&&t.x2==ex2&&t.y2==ey2){
            res=t.step;
            break;
        }
        for(int i=0;i<9;i++){
            int t1;
            x1=t.x1+dx[i];
            y1=t.y1+dy[i];
            //遇到障碍,跳过
            if(g[x1][y1]==-1) continue;
            t1 = g[x1][y1];
            g[x1][y1]=8;
            for(int j=0;j<9;j++){
                int t2;
                x2 =t.x2+dx[j];
                y2 =t.y2+dy[j];
                if(g[x2][y2]==-1)continue;
                //如果访问过,就跳过
                if(visit[x1][y1][x2][y2]==1) continue;
                //如果两个坦克不相邻(8个方向)
                if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)>2){
                    t2=g[x2][y2];
                    g[x2][y2]=9;
                    visit[x1][y1][x2][y2]=1;
                    queue[tail].x1=x1;
                    queue[tail].y1=y1;
                    queue[tail].x2=x2;
                    queue[tail].y2=y2;
                    queue[tail++].step=t.step+1;
                    g[x2][y2]=t2;
                }
            }
            g[x1][y1]=t1;
        }

    }
    return res;
}
LeetCode 994 腐烂的橘子

算法题整理:bfs多源BFS问题 模板_图论_08

算法题整理:bfs多源BFS问题 模板_#include_09

算法题整理:bfs多源BFS问题 模板_#include_10

class Solution {
public:
struct node{
    int x;
    int y;
    int min;
    node(){};
    node(int x,int y,int min):x(x),y(y),min(min){};
}queue[100000];
int head=0;
int tail=0;
bool vis[11][11];
int bfs(vector<vector<int>>&grid){
    int res=0;
     int n=grid.size();
     int m=grid[0].size();
     int cnt=0;
     for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(grid[i][j]==2){
                node t=node(i,j,0);
                queue[tail++]=t;
            }
            if(grid[i][j]==1)cnt++;
        }
     }
     int dx[4]={0,1,0,-1};
     int dy[4]={1,0,-1,0};
     while(head<tail){
        int size=tail-head;
        for(int k=0;k<size;k++){
          node t=queue[head++];
          int x=t.x;
          int y=t.y;
          vis[x][y]=true;
          int minute=t.min;
          res=max(res,minute);
          for(int i=0;i<4;i++){
             int nx=x+dx[i];
             int ny=y+dy[i];
             if(!(nx>=0&&nx<n&&ny>=0&&ny<m))continue;
             if(grid[nx][ny]!=1)continue;
             if(vis[nx][ny])continue;
             vis[nx][ny]=true;
             grid[nx][ny]=2;
             cnt--;
             node nt=node(nx,ny,minute+1);
             queue[tail++]=nt;
          }
        }
     }
     if(cnt!=0)return -1;
     return res; 
}
    int orangesRotting(vector<vector<int>>& grid) {
        memset(vis,0,sizeof(vis));
        return bfs(grid);
    }
};
LeetCode1926   迷宫中的离入口最近的出口

算法题整理:bfs多源BFS问题 模板_图论_11

算法题整理:bfs多源BFS问题 模板_#include_12

算法题整理:bfs多源BFS问题 模板_i++_13

class Solution {
private:
  struct node{
    int x;
    int y;
    int step;
    node(){};
    node(int _x,int _y,int _step):x(_x),y(_y),step(_step){};
  }queue[100001];
  bool vis[101][101];
  int bfs(vector<vector<char>>&g,vector<int>&st){
      int n=g.size();
      int m=g[0].size();
      int head=0;
      int tail=0;
      //初始化队列 
      for(int i=0;i<n;i++){
        if(g[i][0]=='.'&&(!(st[0]==i&&st[1]==0))){
            node t=node(i,0,0);
            queue[tail++]=t;
            cout<<i<<" "<<0<<endl;
            
        }
        if(g[i][m-1]=='.'&&!(i==st[0]&&m-1==st[1])){
            node t=node(i,m-1,0);
            queue[tail++]=t;
        }
      }
      for(int i=0;i<m;i++){
         if(g[0][i]=='.'&&!(0==st[0]&&i==st[1])){
            node t=node(0,i,0);
            queue[tail++]=t;
         }
         if(g[n-1][i]=='.'&&!(n-1==st[0]&&i==st[1])){
            node t=node(n-1,i,0);
            queue[tail++]=t;
         }
      }
      int dx[4]={1,0,-1,0};
      int dy[4]={0,-1,0,1};
      while(head<tail){
         int size=tail-head;
         for(int i=0;i<size;i++){
            node t = queue[head++];
            vis[t.x][t.y]=true;
            if(t.x==st[0]&&t.y==st[1]){
                return t.step;
            }
            for(int k=0;k<4;k++){
                int nx=t.x+dx[k];
                int ny=t.y+dy[k];
                if(!(nx>=0&&nx<n&&ny>=0&&ny<m))continue;
                if(vis[nx][ny])continue;
                if(g[nx][ny]=='+')continue;
                vis[nx][ny]=true;
                node nt=node(nx,ny,t.step+1);
                queue[tail++]=nt;
            }
         }
      }
      return -1;
  }
public:
    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
        memset(vis,0,sizeof(vis));
        return bfs(maze,entrance);
    }
};
LeetCode 934最短的桥

算法题整理:bfs多源BFS问题 模板_图论_14

算法题整理:bfs多源BFS问题 模板_图论_15

bool vis[101][101];
int n,m;
vector<vector<int>>g;
int bfs(){
    queue<vector<int>>q;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(g[i][j]==2)
                 vector<int>t={i,j,0};
                  q.push(t);
       
    int dx[4]={1,0,-1,0};
    int dy[4]={0,1,0,-1};
    while(!q.empty()){
        int size=q.size();
        for(int i=0;i<size;i++){
             vector<int>t=q.front();
             q.pop();
             vis[t[0]][t[1]]=true;
             if(g[t[0]][t[1]]==1)return t[2];
             for(int k=0;k<4;k++){
                    int nx=t[0]+dx[k];
                    int ny=t[1]+dy[k];
                    if(!(nx>=0&&nx<n&&ny>=0&&ny<m))continue;
                    if(vis[nx][ny])continue;
                    vector<int>nt={nx,ny,t[2]+1};
                   q.push(nt);
               }
           }
        }
        return -1;
    }
    void dfs(int x,int y,int flag){
        if(!(x>=0&&x<n&&y>=0&&y<m))return;
        if(g[x][y]!=1)return;
        if(flag==1)g[x][y]=2;
        dfs(x+1,y,flag);
        dfs(x-1,y,flag);
        dfs(x,y-1,flag);
        dfs(x,y+1,flag);
    }
    int shortestBridge(vector<vector<int>>& grid) {
        g=grid;
        n=g.size();
        m=g[0].size();
        int cnt=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j]==2||g[i][j]==0)continue;
                if(cnt==0){
                    dfs(i,j,1);
                    cnt++;
                }
            }
        }
        return bfs()-1;
   }
LeetCode 1293网格中的最短路径

bfs加一维。

算法题整理:bfs多源BFS问题 模板_#include_16

算法题整理:bfs多源BFS问题 模板_#include_17

因为一个点可能被周围4个点更新,如果使用vis数组,只更新了一次就停止更新,这样会错失其他3个点的更新。

如果是普通的bfs求最短路,可以使用vis数组,因为如果一个点被访问到了,那么它的距离就是最短的,之后可以不用被更新。但是多了一维之后,第一次访问到的不一定是最短的,所以需要一直更新。

算法题整理:bfs多源BFS问题 模板_i++_18

算法题整理:bfs多源BFS问题 模板_图论_19

class Solution {
struct node{
    int x;
    int y;
    int r;
    node(){};
    node(int _x,int _y,int _r):x(_x),y(_y),r(_r){};
}queue[100000];
public:
  int shortestPath(vector<vector<int>>& g, int k) {
        int n=g.size();int m=g[0].size();
        int head=0; int tail=0;
        int dis[41][41][41*41];
        memset(dis,0x3f3f3f3f,sizeof(dis));
        node t=node(0,0,0);
        queue[tail++]=t;
        dis[0][0][0]=0;
        int dx[4]={1,0,-1,0};
        int dy[4]={0,-1,0,1};
        while(head<tail){
              node t=queue[head++];
              int distance = dis[t.x][t.y][t.r];
              if(t.x==n-1&&t.y==m-1)return distance;
              for(int i=0;i<4;i++){
                    int nx=t.x+dx[i];
                    int ny=t.y+dy[i];
                    if(!(nx>=0&&nx<n&&ny>=0&&ny<m))continue;
                    int r=t.r+g[nx][ny];
                    if(r>k)continue;
                    if(distance+1>=dis[nx][ny][r])continue;
                    dis[nx][ny][r]=distance+1;
                    node nt = node(nx,ny,r);
                    queue[tail++] = nt;
               }
        }
        return -1;    
    }
};
 LeetCode 1210 穿过迷宫的最少次数

算法题整理:bfs多源BFS问题 模板_算法_20

算法题整理:bfs多源BFS问题 模板_#include_21

算法题整理:bfs多源BFS问题 模板_算法_22

class Solution {
    struct node{
        int x;
        int y;
        int d;
        node(){};
        node(int _x,int _y,int _d):x(_x),y(_y),d(_d){};
    }queue[100001];
public:
    int dis[101][101][2];
    int minimumMoves(vector<vector<int>>& g) {
         memset(dis,0x3f3f3f3f,sizeof(dis));
         int n=g.size();
         int head=0;
         int tail=0;
         node t=node(0,1,0);
         dis[0][1][0]=0;
         dis[0][0][0]=0;
         queue[tail++]=t;
         while(head<tail){
            node t=queue[head++];
            int distance=dis[t.x][t.y][t.d];
            if(t.x==n-1&&t.y==n-1&&t.d==0)return distance;
            int x=t.x;
            int y=t.y;
            int d=t.d;
            int nx,ny,nd;
            if(y+1<n&&g[x][y+1]==0&&d==0){
                nx=x;ny=y+1;nd=0;
                if(dis[nx][ny][nd]>distance+1){
                    dis[nx][ny][nd]=distance+1;
                    node nt=node(nx,ny,nd);
                    queue[tail++]=nt;
                }
            }
            if(y+1<n&&x-1>=0&&g[x][y+1]==0&&g[x-1][y+1]==0&&d==1){
                nx=x;ny=y+1;nd=1;
                if(dis[nx][ny][nd]>distance+1){
                    dis[nx][ny][nd]=distance+1;
                    node nt=node(nx,ny,nd);
                    queue[tail++]=nt;
                }
            }
        if(d==0&&x+1<n&&y-1>=0&&g[x+1][y]==0&&g[x+1][y-1]==0){
           nx=x+1;ny=y;nd=0;
           if(dis[nx][ny][nd]>distance+1){
                    dis[nx][ny][nd]=distance+1;
                    node nt=node(nx,ny,nd);
                    queue[tail++]=nt;
            }
         }
        if(x+1<n&&g[x+1][y]==0&&d==1){
            nx=x+1;ny=y;nd=1;
            if(dis[nx][ny][nd]>distance+1){
                    dis[nx][ny][nd]=distance+1;
                    node nt=node(nx,ny,nd);
                    queue[tail++]=nt;
            }
        }
        if(x+1<n&&y-1>=0&&g[x+1][y]==0&&g[x+1][y-1]==0&&d==0){
            nx=x+1;ny=y-1;nd=1;
            if(dis[nx][ny][nd]>distance+1){
                    dis[nx][ny][nd]=distance+1;
                    node nt=node(nx,ny,nd);
                    queue[tail++]=nt;
            }
        }
        if(x-1>=0&&y+1<n&&g[x][y+1]==0&&g[x-1][y+1]==0&&d==1){
            nx=x-1;ny=y+1;nd=0;
            if(dis[nx][ny][nd]>distance+1){
                    dis[nx][ny][nd]=distance+1;
                    node nt=node(nx,ny,nd);
                    queue[tail++]=nt;
            }
        }
         }
         return -1;
    }
};