您的位置:首页 > 其它

HDU 1180 诡异的楼梯(广搜、优先队列)

2015-08-08 20:36 295 查看



HDU 1180 诡异的楼梯

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)

Total Submission(s): 10885 Accepted Submission(s): 2704

Problem Description

Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,

他们每隔一分钟就变动一次方向. 比如下面的例子里,一开始楼梯在竖直方向,

一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.

Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)

告诉Harry正好有一个魔法道具可以帮助他

寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.

Input

测试数据有多组,每组的表述如下:

第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,

'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:

'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.

地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.

Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.

Output

只有一行,包含一个数T,表示到达目标的最短时间.

注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,

并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,

Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.

Sample Input

5 5
**..T
**.*.
..|..
.*.*.
S....


Sample Output

7

HintHint
地图如下:



诡异的楼梯,果然诡异啊,这道题需要注意到题的有一句话 Harry每秒只能停留在'.'或'S'和'T'所标记的格子内. 这一句是必须注意到的,我因为刚开始没有看到这句话,而犯了一个大错误,这句话说的是他可以在 ‘ . ’ 、‘ S ’、 ‘ T ’ 这三个位置停留!

好了,废话不多说,下面就说一下这道题的解题!

这道题不难看出是一个广搜求最短路问题,关于广搜,都是那一个样子,都很难出什么大变化,广搜变来变去都是在那一个模板上修改几个变量,增减几个变量而已!

做广搜主要的就是边界条件,那就连看看边界条件是什么吧,四周边界肯定都还是原样,没有什么改变,别急,那中间那个楼梯怎么判断,遇到楼梯只要一步就可以过去了,那如果楼梯当时是处于另外一种方式呢?那就要在那等一秒了,所以秒数就要 +2 了 ,我们都知道,广搜中是按照步数的进行搜索的,那如果遇到步数 +2 的那就不能直接放入队列中,因为可能出现先判断步数大了,那该怎么办呢,这里优先队列就起到了独特的作用了,他可以将放入队列中的元素按照某一设定的排列方式排列!

这是优先队列的结构体定义方式:

struct A

{

int x,y,step;

bool operator < (const A &a) const // 对优先队列中 < 运算符进行重新定义, 按照结构体中的步数元素由小到大排序。

{

return a.step < step;

}

};

附上代码:(代码有点长,本来可以简化的,犹豫时间问题,这个任务就交给大家了!)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
int visit[50][50];      // 用来标记该点是否被搜索过
char str[50][50];
int d[4][2] = {-1,0,1,0,0,1,0,-1};    // 上下右左  四个方向的坐标变化
int n,m;
struct A
{
int x,y,step;
bool operator < (const A &a) const
{
return a.step < step;
}
};
int bfs(int x1,int y1,int x2,int y2)
{
int sx,sy;
priority_queue<A> Q;
A e;
e.x = x1;
e.y = y1;
e.step = 0;
Q.push(e);
visit[x1][y1] = 1;     // 该地点被搜索过标记为 1
while(!Q.empty())
{
e = Q.top();
if(e.x == x2 && e.y == y2)     // 如果寻找到目标,则搜索结束!
break;
Q.pop();
for(int i = 0; i < 4; i++)     // 向四个方向搜索!
{
sx = e.x + d[i][0];
sy = e.y + d[i][1];
if(sy >= 0 && sy < n && sx >= 0 && sx < m && (str[sx][sy] == '.' || str[sx][sy] == 'T' )&& visit[sx][sy] == 0)
{
A e1;
e1.x = sx;
e1.y = sy;
e1.step = e.step + 1;
Q.push(e1);
visit[sx][sy] = 1;
}
if(sy >= 0 && sy < n && sx >= 0 && sx < m && str[sx][sy] == '|' )
{
if(e.y == sy && e.x < sx  && (str[sx + 1][sy] == '.' || str[sx + 1][sy] == 'T' ) && visit[sx + 1][sy] == 0 && sx + 1 < m)
{
A e1;
e1.x = sx + 1;
e1.y = sy;
if(e.step % 2 == 0)
e1.step = e.step + 1;  // 桥是直接可以过的
else
e1.step = e.step + 2;  // 桥不可以直接过,等一秒
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
if(e.y == sy && e.x > sx  && (str[sx - 1][sy] == '.' || str[sx - 1][sy] == 'T' ) && visit[sx - 1][sy] == 0 && sx - 1 >= 0)
{
A e1;
e1.x = sx - 1;
e1.y = sy;
if(e.step % 2 == 0)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
if(e.y < sy && e.x == sx  && (str[sx][sy + 1] == '.' || str[sx][sy + 1] == 'T' ) && visit[sx][sy + 1] == 0 && sy + 1 < n)
{
A e1;
e1.x = sx;
e1.y = sy + 1;
if(e.step % 2 == 1)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
if(e.y > sy && e.x == sx  && (str[sx][sy - 1] == '.' || str[sx][sy - 1] == 'T' ) && visit[sx][sy - 1] == 0 && sy - 1 >= 0)
{
A e1;
e1.x = sx;
e1.y = sy - 1;
if(e.step % 2 == 1)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
}
if(sy >= 0 && sy < n && sx >= 0 && sx < m && str[sx][sy] == '-')
{
if(e.y == sy && e.x < sx  && (str[sx + 1][sy] == '.'  || str[sx + 1][sy] == 'T' )&& visit[sx + 1][sy] == 0 && sx + 1 < m)
{
A e1;
e1.x = sx + 1;
e1.y = sy;
if(e.step % 2 == 1)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
if(e.y == sy && e.x > sx  && (str[sx - 1][sy] == '.' || str[sx - 1][sy] == 'T' ) && visit[sx - 1][sy] == 0 && sx - 1 >= 0)
{
A e1;
e1.x = sx - 1;
e1.y = sy;
if(e.step % 2 == 1)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
if(e.y < sy && e.x == sx && (str[sx][sy + 1] == '.' || str[sx][sy + 1] == 'T') && visit[sx][sy + 1] == 0 && sy + 1 < n)
{
A e1;
e1.x = sx;
e1.y = sy + 1;
if(e.step % 2 == 0)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
if(e.y > sy && e.x == sx && (str[sx][sy - 1] == '.' || str[sx][sy - 1] == 'T' ) && visit[sx][sy - 1] == 0 && sy - 1 >= 0)
{
A e1;
e1.x = sx;
e1.y = sy - 1;
if(e.step % 2 == 0)
e1.step = e.step + 1;
else
e1.step = e.step + 2;
Q.push(e1);
visit[e1.x][e1.y] = 1;
}
}
}
}
if(Q.empty())
return -1; // 找不到则返回 -1 ,这一题中没有这种情况,可以省去!
else
{
while(!Q.empty())   // 每次搜索结束后清空队列
Q.pop();
return e.step;
}
}
int main()
{
while(cin >> m >> n)
{
getchar();
memset(visit,0,sizeof(visit));      //  每次搜索前赋值为 0,记为没有被搜索过
memset(str,'\0',sizeof(str));      //   清空字符串 str
int beginx,beginy,endx,endy;
for(int i = 0; i < m; i++)
{
scanf("%s",str[i]);
for(int j = 0; j < n; j++)
{
if(str[i][j] == 'S')
{
beginx = i;    // 记录其实位置
beginy = j;
}
if(str[i][j] == 'T')
{
endx = i;      // 记录终点位置
endy = j;
}
}
}
int ans = bfs(beginx,beginy,endx,endy);
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: