POJ 3601 Escape from Enemy Territory (二分+BFS+预处理)

8 篇文章 0 订阅
7 篇文章 0 订阅

原题:http://poj.org/problem?id=3501

题意是: 有些士兵完成任务后要返回原地,区域被看成矩形,每个小区域有被看成小正方形。在地图上的某些方格内有敌人。。

他们要返回原地,选择一条路使得路的点距离敌人最近的那个点 距离敌人最远,距离是曼哈顿距离|x-xi|+|y-yi|,如果有多条选择最近的。。输出 这条路上距离敌人最近的点到敌人距离 和 这条路的长度、、

思路:  BFS 可以实现 找出距离敌人最近的点。。。

但是最先要找的是距离敌人最远的距离。。。。 距离的范围是 1到 2000  

二分思路的话 就会变得很小。

所以思路是 利用二分 ,每次BFS求出距离。

距离预处理:由于二分求多次,所以可以把图上的每个点距离敌人的最近距离预处理出来。复杂度O(X*Y)

总体复杂度  O(log(X+Y)*X*Y)   还是 hold住的

同样是BFS

利用队列,把所有敌人的坐标入队。距离标记为0 , 在把每个点(A)相邻的没搜索过的点入队,并且距离=A的距离+1。全图搜索一边,标记完成。。

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

using namespace std;
int t;
int n;// the number of the enemys
int xmax,ymax;//边界
int stx,sty,endx,endy;//开始和终止的坐标
const  int  dx[4]={-1,1,0,0};
const  int  dy[4]={0,0,-1,1};
bool check(int x,int y){ //检查 是否越界
  if(x<1||x>xmax||y<1||y>ymax)
	  return false;
  return true;
}
struct Node{
   int x;
   int y;
   int len;
};// node  在 预处理 距离 和求路的长度是用到,两者len 的意义不一样  , 一个表示据敌人的距离,一个表示据起点的距离  由于结构相同就 使用相同的struct
Node node[1000100];//自己手写的队列 用到
struct queue2{  //自己手写的队列
  int head;
  int tail;
  void init(){
    head=0;
    tail = 0;
  }
  Node front(){
      return node[head];
  }
  void pop(){
      head++;
  }
  void push(Node a){
      node[tail]=a;
      tail++;
  }
  bool empty(){
    if(tail==head)
	 return true;
    return false;
  }
}q={0,0};

bool vis[1010][1010];  // 记录是否搜过
int length[1010][1010]; // 记录据敌人的距离

void init(){  
   for(int i=1;i<=xmax;i++){
     for(int j=1;j<=ymax;j++){     
         vis[i][j]=false;
	 length[i][j]=-1;
     }
   }
}

void init_length(){  //  预处理 length距离数组 
    while(!q.empty()){
       Node a = q.front();
       q.pop();
       int x = a.x;
       int y = a.y;
      for(int i=0;i<=3;i++){ // 向四个方向搜索
          int x2 = x +dx[i];
	  int y2 = y +dy[i];
          if(length[x2][y2]==-1){  // -1 表示没搜过
	     length[x2][y2]=a.len+1;
             Node b = {x2,y2,a.len+1};
	     q.push(b);
	  }
      }
    }
}


void init_vis(){
   for(int  i=1;i<=xmax;i++){
     for(int  j=1;j<=ymax;j++){
        vis[i][j]=false;
     }
   }
}
int cal_dis(int len){ //给定一个 距离敌人的最小距离,判断这个距离能不能到达终点  不能返回 -1 能的话返回长度
    if(length[stx][sty]<len||length[endx][endy]<len)
	    return -1;
    init_vis();
    q.init();//队列初始化
    if(stx==endx&&sty==endy){
      return 0;
    }
    Node a = {stx,sty,0};
    vis[stx][sty]=true;
    q.push(a);
    while(!q.empty()){
        Node top = q.front();
        q.pop();
        for(int i=0;i<=3;i++){
	   int x = top.x+dx[i];
	   int y = top.y+dy[i];
	   if(x==endx&&y==endy){
	         return   top.len+1;
	   }
	   if(check(x,y)&&!vis[x][y]){
	       vis[x][y]=true;
	       if(length[x][y]>=len){
		  Node tmp ={x,y,top.len+1};
	          q.push(tmp);
	       }
	   }
	}
        
    }
    return -1;
}
void  output (){
    int left =1;
    int right =xmax+ymax;
    int mid ;
    int distance;    
    while(left<=right){  // 二分
	  mid =(left +right)>>1;
          distance = cal_dis(mid);
	  
	  if(distance ==-1){
	     right=mid-1; 
	  }else{
	     left =mid+1;
	  }
    }
    cout <<right << " "<<cal_dis(right)<<endl;
    
}
int main(){
   scanf("%d",&t);   
   while(t--){
       scanf("%d%d%d",&n,&xmax,&ymax);
        q.init();
	init();
	scanf("%d%d%d%d",&stx,&sty,&endx,&endy);
	stx++; sty++; endx++;  endy++;  // 自己的是 1 到x  而给定的 0 到x-1,所以要++ 
        for(int i=1;i<=n;i++){
            int x,y ;
	    scanf("%d%d",&x,&y);
	    length[x+1][y+1]=0;
	    vis[x+1][y+1]=true;
	    Node a ={x+1,y+1,0};
	    q.push(a);
       }
       init_length();
       output(); 
   }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值