不同权值的bfs问题
解题思路:
多权bfs可以用优先队列优化以保证每一步都队列中取出的每一步都是最优解,但本题飞机和步行两种方式,先选飞行再选步行可以保证每步采取最优情况。
首先分析状态,可开三维vis数组,vis[x][y][kepp]表示走到(x,y)坐标可以继续续航keep时间所走的步数,由于降落后便可以是空地所以可以贪心飞行。
注意:搜索起点可能无法起飞,搜索终点无法降落等各种踩坑问题。
详解:代码注释
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 200+5;
const int INF = 0x3f3f3f3f;
struct Node{
int x,y,keep;
Node(){};
Node(int xx,int yy,int kk):x(xx),y(yy),keep(kk){};
};
char maze[maxn][maxn];
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int vis[maxn][maxn][105];
//vis[x][y][kepp]走到(x,y)坐标可以继续续航keep时间所走的步数
int n,m,k,sx,sy,ex,ey;
inline bool judge(int &a,int b){
if(a>b){
a = b;
return true;
}
return false;
}
void bfs(){
--sx,--sy,--ex,--ey;
memset(vis,0x3f,sizeof(vis));
queue<Node>q;
q.emplace(sx,sy,0);
vis[sx][sy][0] = 0;
while(!q.empty()){
Node cur = q.front(); q.pop();
int step = vis[cur.x][cur.y][cur.keep];
for(int i=0;i<4;++i){
int nx = cur.x + dir[i][0];
int ny = cur.y + dir[i][1];
if(nx<0||nx>=n||ny<0||ny>=m) continue;
if(maze[cur.x][cur.y]=='.'){
//k==1&&maze[nx][ny]=='.'
//降落后立即起飞贪心飞行
if((k==1&&maze[nx][ny]=='.')||k>1){
if(judge(vis[nx][ny][k-1],step+1)){
q.emplace(nx,ny,k-1);
}
}
if(judge(vis[nx][ny][0],step+2)){
q.emplace(nx,ny,0);
}
}
else if(maze[cur.x][cur.y]=='#'){
//下一个是空地继续降落后立即起飞贪心飞行
if((cur.keep==1&&maze[nx][ny]=='.')||cur.keep>1){
if(judge(vis[nx][ny][cur.keep-1],step+1)){
q.emplace(nx,ny,cur.keep-1);
}
}
}
else if(maze[cur.x][cur.y]=='x'){
if((cur.keep==1&&maze[nx][ny]=='.')||cur.keep>1){
if(judge(vis[nx][ny][cur.keep-1],step+1)){
q.emplace(nx,ny,cur.keep-1);
}
}
else if(cur.keep==0&&maze[nx][ny]!='#'){
if(judge(vis[nx][ny][0],step+2)){
q.emplace(nx,ny,0);
}
}
}
}
}
int ans = vis[ex][ey][0]; //ans初始为vis[ex][ey][0]
//终点可能无法降落,需要提前找地方降落然后走过去
if(maze[ex][ey]=='.'){
for(int i=0;i<=k;++i){
ans = min(ans,vis[ex][ey][i]);
}
}
printf("%d\n",(ans!=INF)?ans:-1);
}
int main(){
while(~scanf("%d%d%d",&n,&m,&k)){
for(int i=0;i<n;++i){
scanf("%s",maze[i]);
}
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
bfs();
}
return 0;
}`