TopCoder: RevolvingDoors BFS算法

题目来源: RevolvingDoors


感觉这道题比前两道应用BFS算法的题目要难一些,不像之前的那么直接,如果这道题目要求的是最短的频数的话,那跟前两道就差不多了,但这里求的是最少旋转门的次数,这就有点复杂了,我的思路如下:

1. 判断当前位置是否是终点,不是则搜索由当前位置可以到达的旋转门,并将旋转之后的结果状态存入LD链表尾。

2. 从LD链表中取出第一个元素作为当前状态,重复步骤1.


遇到的问题:BFS算法需要设置一个访问状态标志,要不然会发生重复搜索同一个状态的情况,开始的时候我只是设置了一个visited数组确定搜索可到达的旋转门的过程不会出现重复搜索的过程,结果出现了大问题,因为搜索过程中,进入LD中的元素会有重复的,所以会进行大量的重复搜索,时间复杂度大大增加,而且遇到某些地图还会出现无限循环的情况,如地图示例1,而地图示例2直接就是算半天算不出来,后来我增加了一个 isVisited函数确保进入LD的元素跟以前进入过的元素没有重复,问题才解决了。

还有一个要注意的问题就是地图示例的情况不是旋转6次,而是7次,最后一次也要先旋转门才能到达终点,开始的程序少算了这一步。


代码如下:

欢迎大家提出改正意见或者在回复里面show上自己的代码微笑

/**
 * TopCoder:RevolvingDoors
 * (http://community.topcoder.com/stat?c=problem_statement&pm=3064&rd=5869)
 * Author: xuzhezhao
 * E-mail: zhezhaoxu@gmail.com
 * Blog: http://blog.csdn.net/xuzhezhaozhao/
 * Date: 2013/6/7
 */

#include <iostream>
#include <string>
#include <list>

using namespace std;

#define MAX 50			/* 地图无数限制数 */
#define DOORS_MAX 10		/* 门数限制 */

class RevolvingDoors
{
public:
	int turns(string map[]);
};

enum Door_State {H, V};		/* 门的状态,H:水平 V:竖直 */
typedef struct CurrentPos{
	int row;			/* 当前所处行 */
	int col;			/* 当前所处列 */
	Door_State door[MAX][MAX];	/* 门状态数组 */
	int door_pos[DOORS_MAX];	/* 门位置信息 */
	int doors_num;			/* 门数量 */
	int turn_doors;			/* trun的门数量 */
}CurrentPos;

static int map_rows = 0;	/* 地图行数 */
static int map_cols = 0;	/* 地图列数 */
static int end_row;		/* 终点所在行数 */
static int end_col;		/* 终点所在列数 */
static int visited[MAX][MAX];

void init(string map[], CurrentPos &curpos);
bool isEnd(CurrentPos curpos);
bool isVisited(list <CurrentPos> LV, CurrentPos curpos);

int main()
{
	RevolvingDoors revolvingdoors;
	
	/* 地图,以 "" 结尾 */
	string map[] = 
	{ 
	"#############",
	"#  #|##|#   #",
	"#   O  O    #",
	"# E || || S #",
	"#    O  O   #",
	"#   #|##|#  #",
	"#############", 
	"" };

	cout << revolvingdoors.turns(map) << endl;
	
	return 0;
}

int RevolvingDoors::turns(string map[])
{
	list <CurrentPos> LC;		/* LC: 内层BFS状态 */
	list <CurrentPos> LD;		/* LD: 外层BFS,turn 操作之后的状态 */
	list <CurrentPos> LV;		/* LV:外层BFS访问状态标志,类似visited数组,保存turn操作之后的状态,以避免重复 */
	CurrentPos curpos, nextpos;
	int row, col;

	init(map, curpos);
	LD.push_back(curpos);

	/* 外层BFS */
	while (!LD.empty()) {
		curpos = LD.front();
		LD.pop_front();

		/* 初始化visited数组 */
		for (int i = 0; i < MAX; i++) {
			for (int j = 0; j < MAX; j++) {
				visited[i][j] = false;
			}
		}

		LC.push_back(curpos);

		/* 内层BFS */
		while (!LC.empty()) {
			curpos = LC.front();
			LC.pop_front();
			row = curpos.row;
			col = curpos.col;
			visited[row][col] = true;

			if (isEnd(curpos)) {
				return curpos.turn_doors;
			}

			/* 可以向上下左右四个方向推进状态 */

			/* 向上走 */
			nextpos = curpos;
			if (row - 1 >= 0 && !visited[row-1][col]) {
				nextpos.row = row - 1;

				if (' ' == map[row-1][col]) {
					LC.push_back(nextpos);
				} else if ('*' == map[row-1][col]) {	/* 进入门的四周区域 */
					/* 门的位置有三种情况 */
					if (row - 2 >= 0 && 'O' == map[row-2][col] && H == curpos.door[row-2][col] ) {
						LC.push_back(nextpos);
					} else if (col + 1 <= map_cols - 1 && 
						'O' == map[row-1][col+1]) {
						if (V == curpos.door[row-1][col+1]) {
							LC.push_back(nextpos);
						} else {	/* turn door */
							nextpos.door[row-1][col+1] = V;
							++nextpos.turn_doors;
							visited[row-1][col] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					} else if (col - 1 >= 0 && 'O' == map[row-1][col-1]) {
						if (V == curpos.door[row-1][col-1]) {
							LC.push_back(nextpos);
						} else {
							nextpos.door[row-1][col-1] = V;
							++nextpos.turn_doors;
							visited[row-1][col] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					}
				}
			}

			/* 向下走 */
			nextpos = curpos;
			if (row + 1 <= map_rows - 1 && !visited[row+1][col]) {
				nextpos.row = row + 1;
				if (' ' == map[row+1][col]) {
					LC.push_back(nextpos);
				} else if ('*' == map[row+1][col]) {
					if (row + 2 <= map_rows - 1 && 'O' == map[row+2][col] &&
						H == curpos.door[row+2][col] ) {
						LC.push_back(nextpos);
					} else if (col + 1 <= map_cols - 1 && 'O' == map[row+1][col+1]) {
						if (V == curpos.door[row+1][col+1]) {
							LC.push_back(nextpos);
						} else {	/* turn door */
							nextpos.door[row+1][col+1] = V;
							++nextpos.turn_doors;
							visited[row+1][col] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					} else if (col - 1 >= 0 &&
						'O' == map[row+1][col-1]) {
						if (V == curpos.door[row+1][col-1]) {
							LC.push_back(nextpos);
						} else {
							nextpos.door[row+1][col-1] = V;
							++nextpos.turn_doors;
							visited[row+1][col] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					}
				}
			}

			/* 向左走 */
			nextpos = curpos;
			if (col - 1 >= 0 && !visited[row][col-1]) {
				nextpos.col = col - 1;
				if (' ' == map[row][col-1]) {
					LC.push_back(nextpos);
				} else if ('*' == map[row][col-1]) {
					if (col - 2 >= 0 && 'O' == map[row][col-2] &&
						V == curpos.door[row][col-2] ) {
						LC.push_back(nextpos);
					} else if (row - 1 >= 0 && 
						'O' == map[row-1][col-1]) {
						if (H == curpos.door[row-1][col-1]) {
							LC.push_back(nextpos);
						} else {	/* turn door */
							nextpos.door[row-1][col-1] = H;
							++nextpos.turn_doors;
							visited[row][col-1] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					} else if (row + 1 <= map_rows - 1 && 'O' == map[row+1][col-1]) {
						if (H == curpos.door[row+1][col-1]) {
							LC.push_back(nextpos);
						} else {
							nextpos.door[row+1][col-1] = H;
							++nextpos.turn_doors;
							visited[row][col-1] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					}
				}
			}

			/* 向右走 */
			nextpos = curpos;
			if (col + 1 <= map_cols - 1 && !visited[row][col+1]) {
				nextpos.col = col + 1;
				if (' ' == map[row][col+1]) {
					LC.push_back(nextpos);
				} else if ('*' == map[row][col+1]) {
					if (col + 2 <= map_cols - 1 && 'O' == map[row][col+2] &&
						V == curpos.door[row][col+2] ) {
							LC.push_back(nextpos);
					} else if (row + 1 <= map_rows - 1 && 
						'O' == map[row+1][col+1]) {
						if (H == curpos.door[row+1][col+1]) {
							LC.push_back(nextpos);
						} else {	/* turn door */
							nextpos.door[row+1][col+1] = H;
							++nextpos.turn_doors;
							visited[row][col+1] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					} else if (row - 1 >= 0 &&
						'O' == map[row-1][col+1]) {
						if (H == curpos.door[row-1][col+1]) {
							LC.push_back(nextpos);
						} else {
							nextpos.door[row-1][col+1] = H;
							++nextpos.turn_doors;
							visited[row][col+1] = true;
							if (!isVisited(LV, nextpos)){
								LV.push_back(nextpos);
								LD.push_back(nextpos);
							}
						}
					}
				}
			}
		}
	}
	return -1;
}

/**
 * 初始操作,获得地图的基本信息,行,列,门状态。并将门四周的4个点置为 '*' 字符,将 S, E 置为' '(空格)。
 */
void init(string map[], CurrentPos &curpos)
{
	int i, j;
	
	curpos.turn_doors = 0;

	while (map[map_rows] != "") {
		++map_rows;
	}
	if (map_rows > 0) {
		map_cols = map[0].length();
	}

	for (i = 0; i < map_rows; i ++) {
		for (j = 0; j < map_cols; j++) {
			if ('S' == map[i][j]) {
				curpos.row = i;
				curpos.col = j;
				map[i][j] = ' ';
			}
			if ('E' == map[i][j]) {
				end_row = i;
				end_col = j;
				map[i][j] = ' ';
			}
		}
	}
	curpos.doors_num = 0;
	for (i = 0; i < map_rows; i ++) {
		for (j = 0; j < map_cols; j++) {
			if ('O' == map[i][j]) {
				curpos.door_pos[curpos.doors_num] = i * map_cols + j;
				++curpos.doors_num;
				if ('|' == map[i+1][j]) {
					curpos.door[i][j] = V;
				} else {
					curpos.door[i][j] = H;
				}
				map[i+1][j] = map[i-1][j] =
					map [i][j+1] = map[i][j-1] = '*';
			}
		}
	}
}

/**
 * 判断是否到达终点
 */
bool isEnd(CurrentPos curpos)
{
	if (curpos.row == end_row && curpos.col == end_col) {
		return true;
	} else {
		return false;
	}
}

/**
 * 外层BFS访问标志,若LV中含有curpos状态,返回true,否则返回false
 */
bool isVisited(list <CurrentPos> LV, CurrentPos curpos)
{
	list<CurrentPos>::iterator it;
	int door_row, door_col;
	bool flag;
	if (LV.empty()) {
		return false;
	}
	for (it = LV.begin(); it != LV.end(); it++) {
		if (it->row == curpos.row && it->col == curpos.col) {
			flag = true;
			for (int i = 0; i < curpos.doors_num; i++) {
				door_row = curpos.door_pos[i] / map_cols;
				door_col = curpos.door_pos[i] % map_cols;
				if (it->door[door_row][door_col] != curpos.door[door_row][door_col]) {
					flag = false;
					break;
				}
			}
			if (flag) {
				return true;
			}
		}
	}
	return false;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值