BFS【古希腊之争(二)】(bfs+优先队列)

题目描述
话说,年轻的斯巴达勇士们终于走出迷宫,取得胜利并顺利赶了回来。可是等他们回到斯巴达的时候才发现,雅典人趁他们不在偷袭了城邦,并抓走了他们的爱人。侥幸逃出来的几个人说,她们被关押在一个迷宫的牢房里,并把关押她们的迷宫里的情况告诉了年轻的勇士:迷宫中的”S”点表示迷宫的入口,”T”点表示迷宫中牢房的位置,”.”表示空地,可以通过,”#”表示墙,不能直接通过,”K”表示陷阱,一旦进入就必死无疑。每次只能向上下左右四个方向移动,每移动一个单位距离需要耗费一个单位时间,所有斯巴达勇士的移动速度相同。
又是迷宫!!!这次斯巴达的勇士们彻底愤怒了!What’s more, today is the Magpie Festival!
由于斯巴达的勇士们无比愤怒,而且她们也想尽可能的在今天就能救出他们的爱人。所以当他们在迷宫中遇到墙的阻碍时,也能破墙进入。不过破墙的过程会花费一个单位的时间。现在请你计算一下他们最短需要多少时间才能找到迷宫的牢房。
PS:假设迷宫中每个点可以容纳的人数没有限制,每个斯巴达勇士的行动方向之间没有影响。
输入格式
每组测试数据第一行输入二个数n,m(2=<m<=n<=100)分别代表迷宫的长度和宽度。下面n行每行有m个字符用来表示迷宫地图。
0 0表示输入结束,详细输入格式见样例。
输出
输出一个整数,表示找到迷宫出口的最短时间,每组输出占一行。如不能找到出口输入-1
样例输入
3 4
S#.#
..K.
KKT.
0 0
样例输出
8
 


STL 中优先队列的使用方法(priority_queu)

优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。这点类似于给队列里的元素进行了由大互小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。  

基本操作:

empty() 如果队列为空返回真

pop() 删除对顶元素

push() 加入一个元素

size() 返回优先队列中拥有的元素个数

top() 返回优先队列对顶元素

在默认的优先队列中,优先级高的先出队。在默认的int型中先出队的为较大的数。

使用方法:

头文件:

#include <queue>

 

声明方式:

1、普通方法:

priority_queue<int>q;   //通过操作,按照元素从大到小的顺序出队

priority_queue<int,vector<int>, greater<int> >q;  //通过操作,按照元素从小到大的顺序出队

2、自定义优先级:

struct cmp {     

  operator bool ()(int x, int y)     

  {        

     return x > y; // x小的优先级高       //也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高

  }

};

priority_queue<int, vector<int>, cmp>q;    //定义方法

//其中,第二个参数为容器类型。第三个参数为比较函数。

 

3、结构体声明方式:

struct node {     

  int x, y;     

  friend bool operator < (node a, node b)     

  {         

    return a.x > b.x;    //结构体中,x小的优先级高     

  }

};

priority_queue<node>q;   //定义方法

//在该结构中,y为值, x为优先级。

//通过自定义operator<操作符来比较元素中的优先级。

//在重载”<”时,最好不要重载”>”,可能会发生编译错误

内容来自:https://www.cnblogs.com/yaoyueduzhen/p/4456430.html


原来的迷宫bfs 先让最近一圈(1)的入列,再从第一个入列的最近一圈找点入列,再在(1)最近一圈找点入列。

而这道题涉及到了不同的权值,什么意思?原来的题(比如古希腊之争(一))的每个点的前进都是1个权值,所有前进的点的权值是一样的,随意的入队出队顺序不会影响。而这题有了破墙,也就是有的点前进权值是2,有的点前进权值是1,在这样的入列出列中找到去终点的权值最小的一条。所以我们要通过一定的手段去调整入队出队的顺序。


举例子图:

 


然后我们用代码来实现:优先队列的重载我们看上面的知识点  一些需要注意的地方看的代码注释  

其中bfs的最后需要是return-1,不然的话在这个代码中刚开始初始化为0,再用now.t去更新,如果找不到出口的话不能输出-1。 并且如果起点终点重合的话直接输出初始化的0就可以了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;

char a[100][100];
int vis[100][100];
int sx,sy,fx,fy;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int n,m;

struct node{
	
	int x;
	int y;
	int t;    //t记录步数 
	friend bool operator <(node c,node d)  ///重载时最好用< 
	{
		return c.t>d.t;      如果a.t>b.t 则认为a<b 
	}
	
}; 

int bfs()
{
		priority_queue<node>que;
		node now,next;
		now.x=sx,now.y=sy,now.t=0;
		que.push(now);
		vis[sx][sy]=0;
		while(que.size())
		{
			now=que.top();que.pop();
			if(now.x==fx&&now.y==fy)
			{
				return now.t;
			}
			for(int i=0;i<4;i++)
			{
				int nx=now.x+dx[i];int ny=now.y+dy[i];
			
				if(nx>=0&&nx<n&&ny>=0&&ny<m&&vis[nx][ny]==-1&&a[nx][ny]!='K')
				{
					next.x=nx;next.y=ny;
				//	que.push(next);
					vis[nx][ny]=0;
					if(a[nx][ny]=='#')
					next.t=now.t+2;
				 	if(a[nx][ny]=='.'||a[nx][ny]=='T')
				 	next.t=now.t+1;
					
					que.push(next);///在确定了接下来的步数后再入优先队列
				}
				
			}
			
			
		}
	
	return -1; 如果达不到终点要输出-1 
}

int main(void)
{
	while(scanf("%d%d", &n, &m)!=EOF)
	{
		if(n==0&&m==0) break;
		
		memset(vis,-1,sizeof(vis));memset(a,'\0',sizeof(a));
		
		for(int i=0;i<n;i++)
		cin>>a[i];

		
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(a[i][j]=='S')
				sx=i,sy=j;
				if(a[i][j]=='T')
				fx=i,fy=j;
			}
		}
		
	int res=bfs();
	if(res==-1)
	printf("-1");
	else if(res!=-1)
	printf("%d\n",res);
	}
return 0;	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值