双向广度搜索 —— 拯救公主(一)

拯救公主

时间限制: 1 Sec   内存限制: 128 MB

[ 提交][ 状态][ 讨论版]

题目描述

公主被妖怪抓到了一个山洞里,为了尽快营救公主,王子决定不回城搬救兵去独自营救。山洞为矩形且十分空旷,其中生活着K个妖怪。幸运的是这些妖怪晚上都会睡觉并且没人守夜。但是若是离妖怪太近就会惊醒它,其他的妖怪也会被惊醒,所以我们要找一条距离所有妖怪都很远的路。我们把山洞分为了n*m个格子,走到相邻的格子(不含对角)王子需要一步,妖怪只占一个格子的大小。王子希望你给他一条尽可能安全的路,你只需要告诉他,这条路上离妖怪最近的时候距离是多少(最少走K步可到则认为最近距离为k)。入口在1行1列,公主在n行m列。

输入

n,m,k(地图为n行*m列,k为妖怪个数)(1<n,m<=1000,1<k<=100)
之后有k行每行两个数xi,yi(表示妖怪在xi行,yi列)

输出

离妖怪最近的距离

样例输入

3 3 2
1 3
3 1

样例输出

1

提示

离妖怪最近的距离


注意:走到哪个位置就计算到每个妖怪的距离,并取最小值,取这条路径上的最小值的最大距离并输出结果


#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
#include<cstdio>
using namespace std;
#define MIN(x,y)    (x<y?x:y)
#define INF 0x3f3f3f3f
const int c[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
int Map[1003][1003],vis[1003][1003],vis2[1003][1003];
int n,m,k,a[1003],b[1003],dp[1003][1003];
struct node{
    int x,y;
    int v;
    friend bool operator < (const node &aa,const node &bb){
        return aa.v<bb.v;
    }
};
bool check(int i,int j)
{
    if(i>=1 && i<=n && j>=1 && j<=m && Map[i][j])   return true;
    else return false;
}
 
int huan(int s,int d)
{
    if (dp[s][d]) return dp[s][d];
    int t,dd=INF;
    for(int i=1;i<=k;i++){
        t=abs(a[i]-s)+abs(b[i]-d);
        if(t<dd)     dd=t;
    }
    dp[s][d]=dd;
    return dd;
}
 
int bfs(int xx,int yy)
{
    int dd=0;
    priority_queue<node> q,p;
    node now,tmp,now2,tmp2;
    now.x=xx;   now.y=yy;   now.v=huan(xx,yy);
    now2.x=n;   now2.y=m;   now2.v=huan(n,m);
    q.push(now);    p.push(now2);
     
    vis[now.x][now.y]=1;
    vis2[now2.x][now2.y]=1;
    while(!q.empty() && !p.empty()){
        now=q.top();    q.pop();
        now2=p.top();   p.pop();
        if(vis2[now.x][now.y]){
            dd=1;
            break;
        }
        if(vis[now2.x][now2.y]){
            dd=2;
            break;
        }
         
        for(int i=0;i<4;i++){
            tmp.x=now.x+c[i][0];
            tmp.y=now.y+c[i][1];
            tmp.v=min(huan(tmp.x,tmp.y),now.v);
            if(check(tmp.x,tmp.y) && !vis[tmp.x][tmp.y]){
                q.push(tmp);
                vis[tmp.x][tmp.y]=1;
            }
             
            tmp2.x=now2.x+c[i][0];
            tmp2.y=now2.y+c[i][1];
            tmp2.v=min(huan(tmp2.x,tmp2.y),now2.v);
            if(check(tmp2.x,tmp2.y) && !vis2[tmp2.x][tmp2.y]){
                p.push(tmp2);
                vis2[tmp2.x][tmp2.y]=1;
            }
        }
    }
    if(dd==1){
        int w=MIN(now.v,now2.v);
        return w;
    }
    else if(dd==2){
        int s=MIN(now.v,now2.v);
        return s;
    }
    else    return 0;
}
 
int main()
{
    while(~scanf("%d%d%d",&n,&m,&k)){
        memset(Map,INF,sizeof(Map));
        memset(vis,0,sizeof(vis));
        memset(vis2,0,sizeof(vis2));
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for(int i=1;i<=k;i++){
            scanf("%d%d",&a[i],&b[i]);
            Map[a[i]][b[i]]=0;
        }
        printf("%d\n",bfs(1,1));
    }
    return 0;
}


运行时间为 : 420 ms


多给几组测试数据:

(1):1000 1000 10
161 203
85 591
494 633
563 935
517 722
595 363
989 174
448 825
902 939
430 386

输出为:98

(2)1000 1000 10
732 474
449 988
119 239
306 233
258 268
627 992
225 792
237 601
72 361
1 951

输出为:232


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黎轩栀海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值