优先队列
优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。这点类似于给队列里的元素进行了由大到小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则,和普通队列不同的是,队首元素是q.top()。
例题
http://acm.hdu.edu.cn/showproblem.php?pid=1242 题意:某人被关在囚笼里等待朋友解救,问能否解救成功,最少需要多少时间~ 具体:可同时有几个朋友,每走一格消耗一分钟的时间 ,地图上还存在着卫兵,卫兵可以解决掉,但是要另外花费一分钟~
分析:从“a”出发,此题可以用回溯法进行深搜,但那样做的话,效率还是不能让人满意,但是广搜的话,由于入队后每次出队时,根据地图情况的不同,出队元素所记忆的时间并不是层次递增的,因此使用简单广搜的话,同样需要全部搜索才能找到正确答案。
有没有一种方法能让某一步因为遇到士兵而多花时间的结点在队列中向后推迟一层出队呢?
在这里我们可以用优先队列来实现,总体思想上是: 根据时间进行优先性选择,每次都要出队当前队列元素中记录时间最少的出队,而入队处理时,我们可以按顺序对四个方向上的各种情况按正常处理入队就行了,出队顺序由优先队列根据预设优先性自动控制。这样,我们就可以从“a”进行基于优先队列的范围搜索了,并且在第一 次抵达有朋友的位置时得到正确结果~具体实现代码:
/*HDU 1242 基于优先队列的范围搜索,/
#include<stdio.h>
#include<queue>
using namespace std;
#define M 201
typedef struct p{
int x,y,t;
bool operator < (const p &a)const
{
return t>a.t;
}
}Point;
char map[M][M];
Point start;
int n,m;
int dir[][2]={{1,0},{-1,0},{0,1},{0,-1}};
int bfs()
{
priority_queue<Point>que;
Point cur,next;
int i;
map[start.x][start.y]='#';
que.push(start);
while(!que.empty()){
cur=que.top();
que.pop();
for(i=0;i<4;i++){
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
next.t=cur.t+1;
if(next.x<0||next.x>=n||next.y<0||next.y>=m)
continue;
if(map[next.x][next.y]=='#')
continue;
if(map[next.x][next.y]=='r')
return next.t;
if(map[next.x][next.y]=='.'){
map[next.x][next.y]='#';
que.push(next);
}
else if(map[next.x][next.y]=='x'){
map[next.x][next.y]='#';
next.t++;
que.push(next);
}
}
}
return -1;
}
int main()
{
int i,ans;
char *p;
while(scanf("%d%d",&n,&m)!=-1){
for(i=0;i<n;i++){
scanf("%s",map[i]);
if(p=strchr(map[i],'a')){
start.x=i;
start.y=p-map[i];
start.t=0;
}
}
ans=bfs();
printf(ans+1?"%d\n":"Poor ANGEL has to stay in the prison all his life.\n",ans);
}
return 0;
}
|