弱校胡策 大逃亡(BFS灌水+二分答案)

题目描述
给出数字 N(1<=N<=10000), (1<=x<=1000), Y(1<=Y<=1000) ,代表有N 个敌人分布一个 X 行 Y 列的矩阵上,矩形的行号从 0 到 X-1,列号从 0 到Y-1 再给出四个数字 x1,y1,x2,y2,代表你要从点(x1,y1)移到(x2,y2)。在移动的过程中你当然希望离敌人的距离的最小值最大化,现在请求出这个值最大可以为多少,以及在这个前提下,你最少要走多少步才可以回到目标点。注意这里距离的定义为两点的曼哈顿距离,即某两个点的坐标分为 (a,b),(c,d),那么它们的距离为|a-c|+|b-d|。
输入描述
第一行给出数字 N, X, Y 第二行给出 x1,y1,x2,y2 下面将有 N 行,给出 N 个敌人所在的坐标
输出描述
在一行内输出你离敌人的距离及在这个距离的限制下,你回到目标点最少要移动多少步。
样例输入
2 5 6
0 0 4 0
2 1 2 3
样例输出
2 14
数据范围及提示
30%: n=1
100%:1<=n<=1000 ,1<=x<=1000, 1<=y<=1000

题目来源:黄学长博客http://hzwer.com/4598.html

这题就是先用一个灌水法处理出每个点到最近的点的距离。然后二分到敌人的距离,输出步数。
这题别忘了对起点判断距离是否合法!!!被随机数据卡死在没判断这个。。。。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1005;
bool vis[maxn][maxn];
int dis[maxn][maxn];
struct dqs
{
    int x,y,step;
}hh[maxn];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
queue<dqs>q;
int n,x,y,sx,sy,ex,ey,ans=0,r;
int xex,yey;
bool check(int xx,int yy)
{
    if(xx>=0&&xx<x&&yy>=0&&yy<y&&!vis[xx][yy])
        return true;
    return false;
}
void waterfill()
{
    for(int i=1;i<=n;i++)
    {
        dqs now;
        now.x=hh[i].x;
        now.y=hh[i].y;
        now.step=0;
        q.push(now);
    }
    while(!q.empty())
    {
        dqs head=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            dqs now;
            now.x=head.x+dx[i];
            now.y=head.y+dy[i];
            if(check(now.x,now.y))
            {
                vis[now.x][now.y]=1;
                now.step=head.step+1;
                dis[now.x][now.y]=now.step;
                r=max(r,now.step);
                q.push(now);
            }
        }
    }
}
bool bfs(int mid)
{
    dqs fir;
    fir.x=sx;
    fir.y=sy;
    fir.step=0;
    vis[fir.x][fir.y]=1;
    if(dis[fir.x][fir.y]<mid)   return false; //之前没有加该语句判断起点是否合法 
    q.push(fir);
    while(!q.empty())
    {
        dqs head=q.front();
        q.pop();
        dqs now;
        for(int i=0;i<4;i++)
        {
            now.x=head.x+dx[i];
            now.y=head.y+dy[i];
            if(now.x>=0&&now.x<x&&now.y>=0&&now.y<y&&!vis[now.x][now.y]&&dis[now.x][now.y]>=mid)
            {
                vis[now.x][now.y]=1;
                now.step=head.step+1;
                if(now.x==ex&&now.y==ey)
                {
                    ans=now.step;
                    return true;
                }
                q.push(now);
            }
        }   
    }
    return false;
}
bool erfen(int x)
{
    while(!q.empty())
        q.pop();
    memset(vis,0,sizeof(vis));
    if(bfs(x)) return true;
    return false;
}
int main()
{
    scanf("%d%d%d",&n,&x,&y);
    int xx,yy;
    scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&xx,&yy);
        hh[i].x=xx;
        hh[i].y=yy;
        hh[i].step=0;
        vis[hh[i].x][hh[i].y]=1;
        dis[hh[i].x][hh[i].y]=0;
    }
    waterfill();
    int l=0;
    r+=1;
    while(r-l>1)
    {
        int mid=(l+r)>>1;
        if(erfen(mid))  l=mid;      
        else r=mid;
    }
    printf("%d %d",l,ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值