双向搜索+DP——拯救公主(二)

拯救公主2

时间限制: 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<=n*m)
之后有k行每行两个数xi,yi(表示妖怪在xi行,yi列)

输出

离妖怪最近的距离

样例输入

3 3 2
1 3
3 1

样例输出

1

提示


k值变大

最近距离的算法为行数差加列数差(即从入口到公主的最短距离为(n-1)+(m-1))。


该题中:妖怪数目变大

程序的优化是:在计算最近距离时,先计算每行的离妖怪距离最近的值,更新过地图数组 Map 后,再每列用 DP 思想,一次从上到下地更新地图的值,再一次从下向上更新,继而取得每个点上距离每个妖怪的最近距离

源程序为:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
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,ax[1003][1003],by[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 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=Map[xx][yy];
	now2.x=n;	now2.y=m;	now2.v=Map[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(Map[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(Map[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(ax,INF,sizeof(ax));
		memset(by,INF,sizeof(by));
		
		int a,b;
		for(int i=1;i<=k;i++){
			scanf("%d%d",&a,&b);
			Map[a][b]=0;
			for(int j=1;j<=m;j++)
				Map[a][j]=MIN(Map[a][j],abs(b-j));
		}	
		for(int i=1;i<=m;i++){
			ax[1][i]=Map[1][i];
			for(int j=2;j<=n;j++){
				if(ax[j-1][i]+1<Map[j][i])
					ax[j][i]=ax[j-1][i]+1;
				else	ax[j][i]=Map[j][i];
			}
			
			by[n][i]=Map[n][i];
			for(int d=n-1;d>=1;d--){
				if(by[d+1][i]+1<Map[d][i])
					by[d][i]=by[d+1][i]+1;
				else	by[d][i]=Map[d][i];
			}
		}
		
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				Map[i][j]=MIN(ax[i][j],by[i][j]);
			}
		}
		printf("%d\n",bfs(1,1));
	}
	return 0;
}

运行时间:580ms


测试数据:

 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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

黎轩栀海

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

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

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

打赏作者

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

抵扣说明:

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

余额充值