3094Escape from Enemy Territory——zoj

思路
 
因为题中说了曼哈顿距离   所以在遍历中  每走一步就是一个距离   就缩小了难度(业界良心。。)
又说要找最小最大距离。。
对于每一个点的预处理最小距离就是一定了


然后再找到那个最小最大距离
然后再来找步数

两个一定要分开找  不然时间上要t


因为找标准要logn次   就要清理logn次哈希表  如果把标准与步数一起更新  就要清理2*logn次哈希表
如果分开找  就只用清理logn+1次哈希表   就不会超时了。。。。 


预处理

dis[i][j]表示i,j到最近的一个敌营的距离
如果暴力来  时间上o(n^3)1000*1000*1000t定了
就要机智一点,,
用bfs来实现   将所有敌营加到队列里   如果当前点的距离算过了
就continue   因为bfs先到的一定是最短距离
这样就只有o(n^2)
ok了。

找最小最大距离
这个肯定二分找了。。。不然呢、
在预处理的时候   记录下所有距离中的最大值  
最小值就不管了  一定是0 (没想到军爷(不用在意这些细节)们居然可以直接穿过敌营  七进七出还战术撤退啊。。。O(∩_∩)O~)
具体步骤见后代码


找到最小步数
裸bfs无压力
找到了二分出来的标准
就用标准来进行真实意义上的bfs
找到最短路
判断如果当前的距离在标准允许内就push  不然就continue





#include<iostream>/*预处理出i,j点到敌营 的最小值  先二分bfs找到一个离敌营最大值   在用标准bfs出最小步数*/
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int dx[5]={0,-1,1,0,0};
const int dy[5]={0,0,0,-1,1};
int hash[1000+10][1000+10];//最小step
int ste[1000+10][1000+10];//最少step 
int maxn;
int l,r,mid;
struct edge
{
	int v,u;
	int step;
	int mins;
}cs,ns,ans,res;
queue<edge>q;
int dis[1000+10][1000+10];
int t;
int n,x,y;
int stx,sty,enx,eny;
void readdata()
{
	maxn=-1;
	while(!q.empty())
	q.pop();
	cs.step=0;
	cs.mins=0;
	cs.u=0;
	cs.v=0;
	ans=cs;
	memset(dis,0,sizeof(dis));
	memset(ste,0,sizeof(ste));
	scanf("%d%d%d",&n,&x,&y);
	scanf("%d%d%d%d",&stx,&sty,&enx,&eny);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&cs.u,&cs.v);
		dis[cs.u][cs.v]=-1;
		q.push(cs);
	}
}
void ready()
{
	while(!q.empty())
	{
		cs=q.front();
		q.pop();
		for(int i=1;i<=4;i++)
		{
			ns=cs;
			ns.u+=dx[i];
			ns.v+=dy[i];
			ns.step++;
			if(ns.u<=x-1&&ns.u>=0)
			if(ns.v<=y-1&&ns.v>=0)
			if(!dis[ns.u][ns.v])
			{
				dis[ns.u][ns.v]=ns.step;
				maxn=max(maxn,dis[ns.u][ns.v]);
				q.push(ns);
			}
		}
	}
	while(!q.empty())
	q.pop();
}
bool bfs_for_bz(int bz)
{
	memset(hash,0,sizeof(hash)) ;
	cs.u=stx;
	cs.v=sty;
	cs.mins=dis[stx][sty];
	q.push(cs);
	while(!q.empty())
	{
		cs=q.front();
		q.pop();
		for(int i=1;i<=4;i++)
		{
			ns=cs;
			ns.u+=dx[i];
			ns.v+=dy[i];			
			if(!(ns.u<=x-1&&ns.u>=0))
			continue;
			if(!(ns.v<=y-1&&ns.v>=0))
			continue;
			ns.mins=min(ns.mins,dis[ns.u][ns.v]);
			if(dis[ns.u][ns.v]==-1)
			ns.mins=0;
			if(ns.mins<bz)
			continue;
			if(hash[ns.u][ns.v]==0)
			{
				if(ns.u==enx&&ns.v==eny)
				{					
					while(!q.empty())
					q.pop();
					return true;
				}
				hash[ns.u][ns.v]=1;				
				q.push(ns);
			}
		}
	}
	return false;
}
int bfs_for_step(int bz)
{
	cs.u=stx;
	cs.v=sty;
	cs.step=0;
	q.push(cs);
	while(!q.empty())
	{
		cs=q.front();
		q.pop();
		for(int i=1;i<=4;i++)
		{
			ns=cs;
			ns.u+=dx[i];
			ns.v+=dy[i];
			ns.step++;
			if(!(ns.u<=x-1&&ns.u>=0))
			continue;
			if(!(ns.v<=y-1&&ns.v>=0))
			continue;
			if(dis[ns.u][ns.v]==-1)
			dis[ns.u][ns.v]=0;
			if(dis[ns.u][ns.v]<bz)
			continue;
			if(ste[ns.u][ns.v]==0)
			{
				if(ns.u==enx&&ns.v==eny)
				{					
					while(!q.empty())
					q.pop();
					return ns.step;
				}
				ste[ns.u][ns.v]=1;
				q.push(ns);
			}
		}
	}
}
int main()
{
	scanf("%d",&t);
	for(int tt=1;tt<=t;tt++)
	{
		readdata();
		ready();
		if(enx==stx&&eny==sty)
		{
			printf("%d %d\n",dis[enx][eny],0);
			continue;
		}
		r=maxn;
		l=0;
		int cs=0;
		while(l<=r) 
		{
			mid=(l+r)/2; 
			if(bfs_for_bz(mid))
			l=mid+1;
			else r=mid-1;
		}
		if(mid==l)
		{
			printf("%d %d\n",mid-1,bfs_for_step(mid-1));	
			continue;
		}
		else
		{
			printf("%d %d\n",mid,bfs_for_step(mid));	
			continue;			
		}
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值