poj3501 Escape from Enemy Territory 二分+预处理+bfs

Escape from Enemy Territory
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 2741 Accepted: 752

Description

A small group of commandos has infiltrated deep into enemy territory. They have just accomplished their mission and now have to return to their rendezvous point. Of course they don’t want to get caught even if the mission is already over. Therefore they decide to take the route that will keep them as far away from any enemy base as possible.

Being well prepared for the mission, they have a detailed map of the area which marks all (known) enemy bases, their current position and the rendezvous point. For simplicity, we view the the map as a rectangular grid with integer coordinates (x, y) where 0 ≤ x < X, 0 ≤ y < Y. Furthermore, we approximate movements as horizontal and vertical steps on this grid, so we use Manhattan distance: dist((x1, y1), (x2, y2)) = |x2x1| + |y2y1|. The commandos can only travel in vertical and horizontal directions at each step.

Can you help them find the best route? Of course, in case that there are multiple routes that keep the same minimum distance to enemy bases, the commandos want to take a shortest route that does so. Furthermore, they don’t want to take a route off their map as it could take them in unknown, dangerous areas, but you don’t have to worry about unknown enemy bases off the map.

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:

  • One line with three positive numbers N, X, Y. 1 ≤ N ≤ 10 000 is the number of enemy bases and 1 ≤ X, Y ≤ 1 000 the size of the map: coordinates x, y are on the map if 0 ≤ x < X, 0 ≤ y < Y.

  • One line containing two pairs of coordinates xi, yi and xr, yr: the initial position of the commandos and the rendezvous point.

  • N lines each containing one pair of coordinates x, y of an enemy base.

All pairs of coordinates are on the map and different from each other.

Output

Per testcase:

  • One line with two numbers separated by one space: the minimum separation from an enemy base and the length of the route.

Sample Input

2
1 2 2
0 0 1 1
0 1
2 5 6
0 0 4 0
2 1
2 3

Sample Output

1 2
2 14

Source


题目意思:给出t个敌方地点,我们要选择一条尽可能离所有敌方地点的路最远的路(也就是说所有点离敌方距离的最小值都是最大的)。

首先,我们要预处理一下,把地图上每一个点都算出离敌方地点最近的距离,那么怎么算呢,我们可以把所有的敌方地点都来一遍bfs,那么我们就可以知道了每一个点离敌方地点最近的距离是多少了,这里要注意一点,敌方地点离最近的敌方地点的距离是多少?距离应该是0,因为它和它自己的距离就是0,因为这一点,我wa了半天,也就是,先把map数组里面的所有点初始化为-1,把所有敌方地点变为0,然后进入队列,进行一次bfs,因为bfs的特殊,所以找到的每一个点都是离敌方地点最近的距离。

接着,我们就开始二分,如果二分的距离合适,那么我们是要找最远的路径,因此l=mid+1,如果距离不合适,那么就说明距离太大,r=mid-1,二分的过程是:如果这个点map[i][j]<mid,那么我们就不取这个点,因为我们是假设这个距离就是所有点中的最小值,看是否能找到一条路径是通的,如果通那么这个mid就是成立的,还有一点就是,我们的起点要特判一样,如果起点都已经是map[i][j]<mid,因为我们一定是从起点开始走的,路径上的每一个点都要符合>=mid,所以第一点就直接不合适,应该取更小的mid。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;
struct node
{
    int x;
    int y;
    int step;
} temp;
int dx[4]= {-1,1,0,0};
int dy[4]= {0,0,-1,1};
int ans;
int map[1009][1009];
int vis[1009][1009];
int n,m,A,B,C,D,t,G;
queue<node>q;
void presolve()
{
    while(!q.empty()) q.pop();
    memset(vis,0,sizeof(vis));
    int i,j,k,x,y,step;
    for(i=0; i<=t-1; i++)
    {
        scanf("%d%d",&x,&y);
        map[x][y]=0;
        temp.x=x;
        temp.y=y;
        temp.step=0;
        q.push(temp);
    }
    while(!q.empty())
    {
        temp=q.front();
        q.pop();
        x=temp.x;
        y=temp.y;
        step=temp.step;
        for(k=0; k<=3; k++)
        {
            i=x+dx[k];
            j=y+dy[k];
            if(i>=0&&i<=n-1&&j>=0&&j<=m-1&&map[i][j]==-1)
            {
                temp.x=i;
                temp.y=j;
                temp.step=step+1;
                q.push(temp);
                ans=max(ans,step+1);
                map[i][j]=step+1;
            }
        }
    }
}
int bfs(int mid)
{
    int i,j,k,x,y,step;
    memset(vis,0,sizeof(vis));
    if(map[A][B]<mid) return -1;
    while(!q.empty()) q.pop();
    temp.x=A;
    temp.y=B;
    temp.step=0;
    q.push(temp);
    vis[A][B]=1;
    while(!q.empty())
    {
        temp=q.front();
        q.pop();
        x=temp.x;
        y=temp.y;
        step=temp.step;
        //printf("x==%d y==%d step==%d\n",x,y,step);
        if(x==C&&y==D)
        {
            G=step;
            return 1;
        }
        for(k=0; k<=3; k++)
        {
            i=x+dx[k];
            j=y+dy[k];
            // printf("i==%d j==%d vis==%d map==%d\n",i,j,vis[i][j],map[i][j]);
            if(i>=0&&i<=n-1&&j>=0&&j<=m-1&&!vis[i][j]&&map[i][j]>=mid)
            {
                vis[i][j]=1;
                temp.x=i;
                temp.y=j;
                temp.step=step+1;
                q.push(temp);
            }
        }
    }
    return -1;

}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k;
        ans=0;
        scanf("%d%d%d",&t,&n,&m);
        memset(map,-1,sizeof(map));
        scanf("%d%d%d%d",&A,&B,&C,&D);
        presolve();
        int l=0,r=ans,mid;
        while(l<=r)
        {
            mid=(l+r)/2;
            k=bfs(mid);
            if(k!=-1)
            {
                l=mid+1;
            }
            else r=mid-1;
        }
        printf("%d %d\n",l-1,G);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值