最短路模板
第一行正整数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来做。
简单证明:
可以在所有起点前加一个虚拟起点,这个虚拟起点到所有起点的路径长度为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 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。畅通路径的长度 是该路径途经的单元格总数。
#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求最小操作数
野人与传教士渡河:
N名传教士和N个野蛮人同在一个小河渡口,渡口上只有一条可容M人的小船。
问题的目标是要用这条小船把这2*N个人全部渡到对岸去,条件是在渡河的过程中,河两岸随时都保持传教士人数不少于野蛮人的人数。否则野蛮人会把处于少数的传教士吃掉。如果顺利渡河,返回最小渡河次数,否则返回-1。
(1)河两岸都需要保持这个条件。
(2)渡船的时候也需要保持这个条件。
(3)假设从右岸为终点)可以从右岸载人渡到左岸,也算一次。
为了防止重复渡河,需要有个状态判断是否重复。
未完待续。
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 腐烂的橘子
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 迷宫中的离入口最近的出口
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最短的桥
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加一维。
因为一个点可能被周围4个点更新,如果使用vis数组,只更新了一次就停止更新,这样会错失其他3个点的更新。
如果是普通的bfs求最短路,可以使用vis数组,因为如果一个点被访问到了,那么它的距离就是最短的,之后可以不用被更新。但是多了一维之后,第一次访问到的不一定是最短的,所以需要一直更新。
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 穿过迷宫的最少次数
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;
}
};