HDU 1180 诡异的楼梯 -- 优先队列

/*
思路就是广搜,碰到梯子原地等待,时间加一再入队(优先队列,时间少的队首),找到终点为止。
HDU 1180 诡异的楼梯
*/

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
#define CLR(c,v) (memset(c,v,sizeof(c)))

const int M = 25;
const int inf = 1 << 30;
const char road = '.';
const char t1 = '|';
const char t2 = '-';
const char start = 'S';
const char end = 'T';
const char obstacle = '*';
const char inqueue = '#';

char map[M][M];
int n,m;
int revise[][2] = {{-1,0},
		    	{0,-1},{0,1},
				   {1,0}};
struct _P{
	int x;int y;int minite;
	_P(int x = -1, int y = -1): x(x), y(y) {minite = 0;}
	bool operator < (const _P &a) const {
		return minite > a.minite;
	}
	bool operator == (const _P &a) const {
		return minite == a.minite;
	}
}S;

int BFS(){
	priority_queue <_P > que;
	que.push(S);
	while(!que.empty()){
 		_P now = que.top(); que.pop();
		if (end == map[now.x][now.y]){ // 终点
			return now.minite;
		}
		map[now.x][now.y] = obstacle;
		for (int i = 0; i < 4 ; i++){ // 四个方向
			int next_x = revise[i][0] + now.x;
			int next_y = revise[i][1] + now.y;
			if (next_x >= 0 && next_x < n && next_y >= 0 && next_y < m ){ // 没有出界
				if (map[next_x][next_y] == obstacle){
					continue;
				}else if (map[next_x][next_y] == road || map[next_x][next_y] == end ){ // 如果是路或终点
					_P next = _P(next_x , next_y);
					next.minite = now.minite + 1;
					(map[next_x][next_y] != end)?(map[next_x][next_y] = inqueue):(1);
					que.push(next);
				}else if ((map[next_x][next_y] == t1 || map[next_x][next_y] == t2 )&&  // 如果是梯子
						  ((map[revise[i][0]*2 + now.x][revise[i][1]*2 + now.y] != obstacle)  )){ // 并且梯子的另一边是路
					if (0 == i || 3 == i){ // 上下方向的梯子
						if (revise[i][0]*2 + now.x >= 0 && revise[i][0]*2 + now.x < n  ){// 没有出界
							if ((map[next_x][next_y] == t1 && (now.minite & 1) == 0) || 
								(map[next_x][next_y] == t2 && (now.minite & 1) == 1) ){
								// 梯子恰好能过去
								_P next = _P( revise[i][0]*2 + now.x , now.y);
								next.minite = now.minite + 1;
								//map[next_x][next_y] = obstacle;
								que.push(next);
							}else{  // 如果暂时不能过去
								_P next = _P( now.x , now.y);
								next.minite = now.minite + 1;
								que.push(next);
							}
						}
					}else if (1 == i || 2 == i ){ // 左右方向的梯子
						if (revise[i][1]*2 + now.y >= 0 && revise[i][1]*2 + now.y < m){// 没有出界
							if ((map[next_x][next_y] == t1 && (now.minite & 1) == 1) || 
								(map[next_x][next_y] == t2 && (now.minite & 1) == 0) ){
								// 梯子恰好能过去
								_P next = _P( now.x , revise[i][1]*2 + now.y);
								next.minite += now.minite + 1;
								//map[next_x][next_y] = obstacle;
								que.push(next);
							}else{	// 如果暂时不能过去
								_P next = _P( now.x ,  now.y);
								next.minite += now.minite + 1;
								que.push(next);
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

int main(){
	//freopen("Input.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	while(scanf("%d %d",&n , &m) != EOF ){
		for (int i = 0; i < n ; i ++){
			scanf("%s",map[i]);
			for (int j = 0 ; j < m ; j++){
				if (start == map[i][j]){
					S = _P(i,j);
				}
			}
		}
 		printf("%d\n", BFS() );
	}
	return 0;
}

/*
一些变态的数据:
20 20
-.|...-............S
.-.|...-............
|.-.|...-...........
.|.-.|...-..........
..|.-.|...-.........
-..|.-.|...-........
.-..|.-.|...-.......
..-..|.-.|...-......
...-..|.-.|...-.....
....-..|.-.|...-....
.....-..|.-.|...-...
......-..|.-.|...-..
.......-..|.-.|...-.
........-..|.-.|...-
.........-..|.-.|...
..........-..|.-.|..
...........-..|.-.|.
............-..|.-.|
.............-..|.-.
T.............-..|.-
2 4
...T
S-..
3 4
.|S-
.*|.
T.*.
1 10
S-.|.-.-.T
1 1
T
20 1
S
-
.
-
.
-
.
-
.
-
.
-
.
-
.
-
.
-
.
T
1 2
ST
2 1
T
S
20 20
...................S
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
T...................
20 20
...................T
....................
|*******************
....................
*******************-
....................
|*******************
....................
*******************-
....................
|*******************
....................
*******************|
....................
-*******************
....................
*******************|
....................
-*******************
S...................
5 5
**..T
**.*.
**|..
**.**
S..**
5 5
.*..T
...*.
.-.*.
..|**
S-.**
5 5
.|.-T
-*-*|
.*.|.
-*-**
S|.**
5 5
S....
-|-|-
.....
-|-|-
....T
1 3
S-T
1 3
S|T
1 5
S|.|T
1 5
S-.-T
1 5
S|.-T
1 5
S-.|T
2 2
*T
S|
20 20
**.|.**.-.*|..-.*..T
.*|..-.*..**.-.|*..*
....|..|.|.-..-..|..
.-.**..*...-..-..*..
**.-.**..*-.-..*.*.|
.-...|.|...**..-.*..
.*|.-.-*.|.-.*-*.**.
-..*.*.*-.**.|.|*.*|
.-.*-..-...-..-..|..
-.-..*.**.|.*|.*..*-
.*|..-.*..**.-.|*..*
....|..|.|.-..-..|..
**.-.**..*-.-..*.*.|
.-.*-..-...-..-..|..
.-...|.|...**..-.*..
.*|.-.-*.|.-.*-*.**.
-..*.*.*-.**.|.|*.*|
.-.*-..-...-..-..|..
-.-..*.**.|.*|.*..*-
S|.*.*.|.-*.|.*.|.-.
10 20
**.|.**.-.*|..-.*..T
.*|..-.*..**.-.|*..*
....|..|.|.-..-..|..
**.-.**..*-.-..*.*.|
.-...|.|...**..-.*..
.*|.-.-*.|.-.*-*.**.
-..*.*.*-.**.|.|*.*|
.-.*-..-...-..-..|..
-.-..*.**.|.*|.*..*-
S|.*.*.|.-*.|.*.|.-.
4 9
-..-.-.|T
.*-*..*..
.*.*.***|
S-..*..*.
6 10
.|.*.|.*.T
****.-...*
***..-|*.*
-.**.***..
.-.|.*-*..
S.***-*.**

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值