题目描述:
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
现实世界可以抽象为一张 n×mn \times mn×m 大小的二维地图。PLMM 的初始坐标在 (x1,y1)(x_1,y_1)(x1,y1),活动范围 r1r_1r1 表示 PLMM 只会移动到坐标为 (x,y)(x,y)(x,y) 的位置 (0≤∣x−x1∣+∣y−y1∣≤r1)(0 \leq |x-x_1|+|y-y_1| \leq r_1)(0≤∣x−x1∣+∣y−y1∣≤r1)。小喵的初始坐标在 (x2,y2)(x_2,y_2)(x2,y2),鼻子灵敏度 r2r_2r2 表示小喵只能闻到坐标为 (x,y)(x,y)(x,y) 的位置的小鱼干 (0≤∣x−x2∣+∣y−y2∣≤r2)(0 \leq |x-x_2|+|y-y_2| \leq r_2)(0≤∣x−x2∣+∣y−y2∣≤r2)。此外,地图中存在若干障碍物使得 PLMM 和小喵无法通过。
若 PLMM 或小喵当前的坐标为 (x,y)(x,y)(x,y),则下一步可以移动到 (x−1,y), (x,y−1), (x+1,y)(x-1,y),\,(x,y-1),\,(x+1,y)(x−1,y),(x,y−1),(x+1,y) 或 (x,y+1)(x,y+1)(x,y+1) 坐标的位置。起初,小喵保持原地不动,但当闻到小鱼干的气味时便会朝 PLMM 的位置跑去。在小喵开始移动的同时,PLMM 会担心吓跑小喵从而保持原地不动。需要注意的是,鼻子灵敏度 r2r_2r2 只能决定小喵能否闻到小鱼干的气味,对小喵的移动范围没有限制。小喵闻到小鱼干气味后便会锁定 PLMM 的位置,即使之后闻不到小鱼干的位置,也会继续朝 PLMM 的位置移动。
若小喵可以吃到小鱼干,PLMM 想知道自己与小喵移动的距离和最小值。
思路:
本题是两个BFS,算出人到每个点的距离和猫到每个点的距离相加后求最小值。人是有活动范围而猫没有活动范围,这里在BFS的时候可以看作猫的活动范围无限大。
这里先放最核心的bfs代码,不理解bfs的可以移步至DFS和BFS理解+模板+例题
char s[1005][1005];/*储存地图信息*/
int n,m,r1/*人活动范围*/,r2/*猫嗅觉范围*/;
int dx[]={-1,1,0,0};//用于遍历人/猫上下左右移动的情况
int dy[]={0,0,-1,1};
int dis[2][1005][1005];//储存到起点的距离,0为人1为猫
int mx,my;/*猫的坐标*/
void bfs(int k/*0为人1为猫*/,int x/*起始横坐标*/,int y/*起始纵坐标*/,int r/*活动范围*/){
queue<pair<int,int>> q;
pair<int,int> t;
dis[k][x][y]=0;
q.push({x,y});
while(!q.empty()){
t=q.front();
q.pop();
int nx=t.first;
int ny=t.second;
for(int i=0;i<4;i++){
int nnx=nx+dx[i];
int nny=ny+dy[i];
if(nnx>0 && nnx<=n && nny>0 &&nny<=m&&//目标移动点在范围内
s[nnx][nny]!='*' && dis[k][nnx][nny]==0x3f3f3f3f &&//不是阻挡物而且是没去过的点
abs(nnx-x)+abs(nny-y)<=r)//距离起始点距离不超过r
{
q.push({nnx,nny});
dis[k][nnx][nny]=dis[k][nx][ny]+1;
}
}
}
}
因为要计算每个点到人/猫的最短距离,采用bfs可以确保第一次读到一个点的时候的值就是最小值。计算人时bfs参数的r采用r1,猫则采用0x3f3f3f3f(int的最大值)。
main函数中就是简单的读取和枚举判断点是否符合条件
完整AC代码:
#include<bits/stdc++.h>
using namespace std;
char s[1005][1005];
int n,m,r1/*人活动范围*/,r2/*猫嗅觉范围*/;
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
int dis[2][1005][1005];//储存到起点的距离,0为人1为猫
int mx,my;/*猫的坐标*/
void bfs(int k/*0为人1为猫*/,int x/*起始横坐标*/,int y/*起始纵坐标*/,int r/*活动范围*/){
queue<pair<int,int>> q;
pair<int,int> t;
dis[k][x][y]=0;
q.push({x,y});
while(!q.empty()){
t=q.front();
q.pop();
int nx=t.first;
int ny=t.second;
for(int i=0;i<4;i++){
int nnx=nx+dx[i];
int nny=ny+dy[i];
if(nnx>0 && nnx<=n && nny>0 &&nny<=m&&//目标移动点在范围内
s[nnx][nny]!='*' && dis[k][nnx][nny]==0x3f3f3f3f &&//不是阻挡物而且是没去过的点
abs(nnx-x)+abs(nny-y)<=r)//距离起始点距离不超过r
{
q.push({nnx,nny});
dis[k][nnx][nny]=dis[k][nx][ny]+1;
}
}
}
}
int main(){
cin>>n>>m>>r1>>r2;
memset(dis,0x3f3f3f3f,sizeof(dis));
for(int i=1;i<=n;i++){//读取地图信息
scanf("%s",s[i]+1);//s[i]是字符串数组s[i]的首地址,s[i]+1就意味着从s[i][1]开始存
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]=='P') bfs(0,i,j,r1);/*广搜人能到达地方并储存到那里的距离*/
else if(s[i][j]=='M'){
bfs(1,i,j,0x3f3f3f3f);/*广搜猫能到的地方并储存到那里的距离*/
mx=i;/*储存猫的坐标*/
my=j;
}
}
}
int minn=0x3f3f3f3f;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(abs(i-mx)+abs(j-my)<=r2){//该点在猫嗅觉范围内
minn=min(minn,dis[0][i][j]+dis[1][i][j]);//因为到不了的地方默认int的上限值所以自动排除
}
}
}
if(minn==0x3f3f3f3f) cout<<"-1"<<'\n';//如果minn不变说明没有符合条件的点输出-1
else cout<<minn<<'\n';
return 0;
}