计蒜客-蒜头君回家(bfs)

蒜头君要回家,但是他家的钥匙在他的朋友花椰妹手里,他要先从花椰妹手里取得钥匙才能回到家。花椰妹告诉他:“你家的钥匙被我复制了很多个,分别放在不同的地方。”

蒜头君希望能尽快回到家中,他需要首先取得任意一把钥匙,请你帮他计算出回家所需要的最短路程。

蒜头君生活的城市可以看做是一个 n×m 的网格,其中有道路有障碍,钥匙和家所在的地方可以看做是道路,可以通过。蒜头君可以在城市中沿着上下左右 4 个方向移动,移动一个格子算做走一步。

输入格式

第一行有两个整数 n,m。城市的地图是 n 行 m 列。(1≤n,m≤2000)

接下来的 n 行,每行 m 个字符,代表城市的地图。’.’ 代表道路,’#’ 代表障碍物,’S’ 代表蒜头君所在的位置,’T’ 代表蒜头家的位置,’P’代表钥匙的位置。除了障碍物以外,别的地方都可以通过。(题目保证蒜头君至少有一条路径可以顺利拿到钥匙并且回家)

输出格式

输出蒜头回家要走的最少步数,占一行。

样例输入

8 10
P.####.#P#
..#..#...#
..#T##.#.#
..........
..##.#####
..........
#####...##
###....S##

样例输出

21

解题说明:这里我们并不是先搜索所有钥匙,再从每个每个钥匙出发找终点,这样肯定会超时。

我们就搜一次,真的就一次!搜索的过程中,找到钥匙的,其后面走过的坐标都记标志,标志说明我已经有钥匙了,没有标识,则经过终点也继续搜。记一个flag不行,不同的路径在搜,可能其中一条找到钥匙了,你变了flag,另外的没有钥匙的到了终点判断到了,就错了。

标志的问题,多加一维,已经有钥匙了有没走过,和没有钥匙的走没走过。

ac代码:

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxl 2010
using namespace std;
int n,m;
int a[maxl][maxl],vist[maxl][maxl][2];
int cg[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct point{
	int x;int y;int foot;int flag;
	point(int xx,int yy,int fot,int f){
		x=xx;y=yy;foot=fot;flag=f;
	}
};
int bfs(int x,int y){
	queue<point>q;
	q.push(point(x,y,0,0));
	vist[x][y][0]=1;
	while(!q.empty()){
		point po=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			int tx=po.x+cg[i][0];
			int ty=po.y+cg[i][1];
			if(a[tx][ty]!='#'&&!vist[tx][ty][po.flag]&&tx>0&&tx<=n&&ty>0&&ty<=m){
				vist[tx][ty][po.flag]=1;
				if(a[tx][ty]=='P'){
					q.push(point(tx,ty,po.foot+1,1));
				}
				else if(a[tx][ty]=='T'&&po.flag){
					return po.foot+1;
				}
				
				else q.push(point(tx,ty,po.foot+1,po.flag));
			}
		}
	} 
}
int main(){
	scanf("%d%d",&n,&m);
	memset(vist,0,sizeof(vist));
	int bx,by;
	for(int i=1;i<=n;i++){
		 getchar();
		 for(int j=1;j<=m;j++){
		 	  scanf("%c",&a[i][j]);
		      if(a[i][j]=='S'){
		      	bx=i;by=j;
			  }
		 }
	}	
	printf("%d\n",bfs(bx,by));
	return 0;
}

运行超时代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
#define maxl 2048
using namespace std;
int n,m,ans=0,flag=0;
int a[maxl][maxl],mark[maxl][maxl];long long b[maxl][maxl];
int cgx[4]={1,-1,0,0};
int cgy[4]={0,0,1,-1};
long long mn=100000000000007;
int ex,ey; 
map<int,map<int,int> >mp;
struct point{
	int x;int y;
	point(int xx,int yy){
		x=xx;
		y=yy;
	}
};
struct p{
	int p1;
	int p2;
}pz[maxl*maxl];
void bfs(int x,int y,int index){
    queue<point>q;
    while(!q.empty()){
    	q.pop();
	}
	q.push(point(x,y));
	mark[x][y]=1;
	while(!q.empty()){
		if(index==ans)return ;
		x=q.front().x;
		y=q.front().y;
		q.pop();
		for(int i=0;i<4;i++){
			int tx=x+cgx[i];
			int ty=y+cgy[i];
			if(a[tx][ty]&&!mark[tx][ty]&&tx>0&&tx<=n&&ty>0&&ty<=m){
				  mark[tx][ty]=1;
				  b[tx][ty]=b[x][y]+1;
				  q.push(point(tx,ty));
				  if(a[tx][ty]==2&&!flag){
				  	 mp[tx][ty]=b[tx][ty];
					 index++; 
				  }
				  if(flag&&a[tx][ty]==6){
				  	  return ;
				  }
		    }
	   }	    	
    }
    return ;
}
int main(){
	scanf("%d%d",&n,&m);
	char ip1;int bx,by;
	for(int i=1;i<=n;i++){
		string s;cin>>s;
		for(int j=1;j<=m;j++){
			ip1=s[j-1];
			if(ip1=='S'){
				a[i][j]=1;
				bx=i;by=j;
			}
			else if(ip1=='.')a[i][j]=1;
			else if(ip1=='P'){
				pz[ans].p1=i;pz[ans].p2=j;
				ans++;
				a[i][j]=2;
			}
			else if(ip1=='T'){
				ex=i;ey=j;
				a[i][j]=6;
			} 
			else a[i][j]=0;
		}	
	}
	bfs(bx,by,0);
	for(int i=0;i<ans;i++){
		memset(mark,0,sizeof(mark));
		memset(b,0,sizeof(b));
		if(mp[pz[i].p1][pz[i].p2]){
			 flag=1;
			 bfs(pz[i].p1,pz[i].p2,0);
			 if(b[ex][ey]){
			 	if(mp[pz[i].p1][pz[i].p2]+b[ex][ey]<mn)mn=mp[pz[i].p1][pz[i].p2]+b[ex][ey];
			 }
		}	
	}
	printf("%d\n",mn);
	return 0;
} 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值