poj_1475 BFS+BFS

题目大意

推箱子游戏的基本玩法,求将箱子推到目的地的推动次数最少(并不是人移动总次数)的人移动路径。

题目分析

求最短路径的搜索问题,使用BFS。注意题目求的是 推动次数最少,因此将箱子移动作为状态,求箱子移动最少次数到达目的地的路径,然后在该路径的拐点基础上再次进行 对人移动的BFS搜索。 
    即BFS套BFS。 
    和所有的搜索问题,动态规划问题一样,对程序的每个步骤,都要明确、详尽(主要是可以完整保存所需要的信息,而不是数据量大)的记录状态。本题目中的每个cell,都可以从四个不同的方向进入,因此记录状态时候,需要记录每个点,及其它是从哪个方向进入。 
    我在实现的时候,先按照第一层BFS搜索,找到箱子的最短移动路径,中间记录每个点的前一个点,最后再倒推出箱子的正向移动路径; 然后找出拐点处的人应该移动的位置,再次进行BFS,中间也是保存了每个点的前一个点,最后倒推出正向路径。这样就导致代码长度很长 →_→ !!! 
    这样做,在每个节点需要保存的数据量比较大的时候比较划算,但是每个节点需要保存的就只是一个字符,而总共不超过400个点,即使都用一个string保存下来,内存能应付过来。看网上有人是采用这种方式实现的,确实很精巧!参见POJ_1475

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<queue>
#include<string.h>
#include<stack>
using namespace std;
#define MAX_CASTLE_SIZE 24
#define INFINITE 1 << 30
char gCastle[MAX_CASTLE_SIZE][MAX_CASTLE_SIZE];
bool gWalkVisited[MAX_CASTLE_SIZE][MAX_CASTLE_SIZE];
int gRow, gCol;
int gBoxPos[2];
int gPeoplePos[2];
int gTargetPos[2];

int gMoveInc[5][2] = { { 1, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 }, { 0, 1 } };
char gWalkDirChar[5] = { ‘t‘, ‘w‘, ‘s‘, ‘n‘, ‘e‘ };
char gPushDirChar[5] = { ‘T‘, ‘W‘, ‘S‘, ‘N‘, ‘E‘ };

struct PushNode{
	int pre_row;
	int pre_col;
	int pre_dir;

	PushNode(int p_r = 0, int p_c = 0, int p_d = 0) :
		pre_row(p_r), pre_col(p_c), pre_dir(p_d){};
};

PushNode gPushNodes[MAX_CASTLE_SIZE][MAX_CASTLE_SIZE][4];

struct WalkNode{
	int pre_row;
	int pre_col;
	int dir_from_pre;
	WalkNode(int p_r = 0, int p_c = 0, int d = 0) :
		pre_row(p_r), pre_col(p_c), dir_from_pre(d){};
};

WalkNode gWalkNodes[MAX_CASTLE_SIZE][MAX_CASTLE_SIZE];

struct PeopleMoveNode{
	bool arrive_by_walk;
	int row;
	int col;
	int dir_to_next;
	int box_x;
	int box_y;
	PeopleMoveNode(bool w = true, int r = 0, int c = 0, int d = 0, int bx = 0, int by = 0) :
		arrive_by_walk(w), row(r), col(c), dir_to_next(d), box_x(bx), box_y(by){};
	void SetInfo(bool w, int r, int c, int d, int bx, int by){
		arrive_by_walk = w;
		row = r;
		col = c;
		dir_to_next = d;
		box_x = bx;
		box_y = by;
	}
};

stack<PeopleMoveNode> gPushNodestack;

void Input(){
	memset(gCastle, ‘#‘, sizeof(gCastle));

	for (int row = 1; row <= gRow; row++){
		getchar();
		for (int col = 1; col <= gCol; col++){
			scanf("%c", &gCastle[row][col]);
			if (gCastle[row][col] == ‘B‘){
				gBoxPos[0] = row;
				gBoxPos[1] = col;
			}
			if (gCastle[row][col] == ‘S‘){
				gPeoplePos[0] = row;
				gPeoplePos[1] = col;
			}
			if (gCastle[row][col] == ‘T‘){
				gTargetPos[0] = row;
				gTargetPos[1] = col;
			}
		}
	}

}

void TraceWay(int start_x, int start_y, int cur_x, int cur_y, bool walk){
	int pre_x = gWalkNodes[cur_x][cur_y].pre_row;
	int pre_y = gWalkNodes[cur_x][cur_y].pre_col;
	if (start_x == cur_x && start_y == cur_y){
		//char dir = walk ? gWalkDirChar[gWalkNodes[cur_x][cur_y].dir_from_pre] : gPushDirChar[gWalkNodes[cur_x][cur_y].dir_from_pre];
		//printf("%c", dir);
		return;
	}

	TraceWay(start_x, start_y, pre_x, pre_y, walk);

	char dir = walk ? gWalkDirChar[gWalkNodes[cur_x][cur_y].dir_from_pre] : gPushDirChar[gWalkNodes[cur_x][cur_y].dir_from_pre];
	printf("%c", dir);
}

void FindMinStepWay(int start_x,int start_y, int end_x, int end_y, int box_x, int box_y){
	memset(gWalkNodes, 0, sizeof(gWalkNodes));

	queue<pair<int, int> > Q;
	pair<int, int> pos_pair(start_x, start_y);
	gWalkNodes[start_x][start_y].pre_row = -1;
	gWalkNodes[start_x][start_y].pre_col = -1;

	Q.push(pos_pair);
	while (!Q.empty()){
		pos_pair = Q.front();
		Q.pop();
		if (pos_pair.first == end_x && pos_pair.second == end_y){
			TraceWay(start_x, start_y, end_x, end_y, true);
			return;
		}
		for (int i = 1; i <= 4; i++){
			int next_x = pos_pair.first + gMoveInc[i][0];
			int next_y = pos_pair.second + gMoveInc[i][1];
			if (gCastle[next_x][next_y] != ‘#‘ && !gWalkNodes[next_x][next_y].pre_row && (next_x != box_x || next_y != box_y)){
				gWalkNodes[next_x][next_y].pre_row = pos_pair.first;
				gWalkNodes[next_x][next_y].pre_col = pos_pair.second;
				gWalkNodes[next_x][next_y].dir_from_pre = i;
				Q.push(pair<int, int>(next_x, next_y));
			}
		}
	}
}

//人从 people_x, people_y 出发,能否walk到(不能推动箱子) pos_x, pos_y, 箱子位于 box_x, box_y
bool CanPushFromPos(int pos_x, int pos_y, int people_x, int people_y, int box_x, int box_y){
	if (gCastle[pos_x][pos_y] == ‘#‘){
		return false;
	}
	if (pos_x == people_x && pos_y == people_y){
		return true;
	}
	memset(gWalkVisited, false, sizeof(gWalkVisited));
	gWalkVisited[people_x][people_y] = true;
	gWalkVisited[box_x][box_y] = true;
	queue<pair<int, int> >Q;
	pair<int, int> pos_pair(people_x, people_y);
	Q.push(pos_pair);
	while (!Q.empty()){
		pos_pair = Q.front();
		Q.pop();
		if (pos_pair.first == pos_x && pos_pair.second == pos_y){
			return true;
		}
		for (int i = 1; i <= 4; i++){
			int next_x = pos_pair.first + gMoveInc[i][0];
			int next_y = pos_pair.second + gMoveInc[i][1];
			if (gWalkVisited[next_x][next_y] || gCastle[next_x][next_y] == ‘#‘){
				continue;
			}
			gWalkVisited[next_x][next_y] = true;
			Q.push(pair<int, int>(next_x, next_y));
		}
	}
	return false;
}

void SetNodeStack(){
	while (!gPushNodestack.empty()){
		gPushNodestack.pop();
	}

	int cur_x = gTargetPos[0], cur_y = gTargetPos[1];
	int last_dir = -1;
	for (int i = 1; i <= 4; i++){
		if (gPushNodes[cur_x][cur_y][i].pre_row){
			last_dir = i;
			break;
		}
	}

	int pre_x = gPushNodes[cur_x][cur_y][last_dir].pre_row;
	int pre_y = gPushNodes[cur_x][cur_y][last_dir].pre_col;

	PeopleMoveNode move_node(false, pre_x, pre_y, last_dir,cur_x ,cur_y);
	gPushNodestack.push(move_node);
	cur_x = pre_x;
	cur_y = pre_y;
	while (true){
		///printf("cur x = %d, cur y = %d\n", cur_x, cur_y);

		if (cur_x == gBoxPos[0] && cur_y == gBoxPos[1]){
			pre_x = cur_x - gMoveInc[last_dir][0];
			pre_y = cur_y - gMoveInc[last_dir][1];

			if (pre_x == gPeoplePos[0] && pre_y == gPeoplePos[1]){
				move_node.SetInfo(false, pre_x, pre_y, last_dir, cur_x, cur_y);
				gPushNodestack.push(move_node);
			}
			else{
				move_node.SetInfo(true, pre_x, pre_y, last_dir, cur_x, cur_y);
				gPushNodestack.push(move_node);

				move_node.SetInfo(false, gPeoplePos[0], gPeoplePos[1], last_dir, cur_x, cur_y);//人开始的起点, arrive_by_walk和last_dir不被使用,随便设
				gPushNodestack.push(move_node);
			}

			break;
		}

		//说明发生了变向
		if (gPushNodes[cur_x][cur_y][last_dir].pre_dir){
			//发生转弯,记录下转弯后,人应该在的位置
			pre_x = cur_x - gMoveInc[last_dir][0];
			pre_y = cur_y - gMoveInc[last_dir][1];
			move_node.SetInfo(true, pre_x, pre_y, last_dir, cur_x, cur_y);
			gPushNodestack.push(move_node);

			last_dir = gPushNodes[cur_x][cur_y][last_dir].pre_dir;

			pre_x = gPushNodes[cur_x][cur_y][last_dir].pre_row;
			pre_y = gPushNodes[cur_x][cur_y][last_dir].pre_col;

			move_node.SetInfo(false, pre_x, pre_y, last_dir, cur_x, cur_y);

			gPushNodestack.push(move_node);
		}
		int tmp = cur_x;
		cur_x = gPushNodes[cur_x][cur_y][last_dir].pre_row;
		cur_y = gPushNodes[tmp][cur_y][last_dir].pre_col;
	}
}
void MoveBox(){
	PeopleMoveNode move_node_from = gPushNodestack.top();
	gPushNodestack.pop();

	PeopleMoveNode move_node_to;
	while (!gPushNodestack.empty()){
		move_node_to = gPushNodestack.top();
		gPushNodestack.pop();

		if (move_node_to.arrive_by_walk){
			FindMinStepWay(move_node_from.row, move_node_from.col, move_node_to.row,
				move_node_to.col, move_node_to.box_x, move_node_to.box_y);
		}
		else{
			int cur_x = move_node_from.row, cur_y = move_node_from.col;
			while (cur_x != move_node_to.row || cur_y != move_node_to.col){
				cur_x = cur_x + gMoveInc[move_node_from.dir_to_next][0];
				cur_y = cur_y + gMoveInc[move_node_from.dir_to_next][1];
				printf("%c", gPushDirChar[move_node_from.dir_to_next]);
			}
		}
		move_node_from = move_node_to;
	}
}

struct PosDirPair{
	unsigned char row;
	unsigned char col;
	unsigned char dir_from_pre;
	void SetInfo(unsigned char r, unsigned char c, unsigned char dir){
		row = r;
		col = c;
		dir_from_pre = dir;
	}
};

void Solve(int cases){
	printf("Maze #%d\n", cases);
	memset(gPushNodes, 0, sizeof(gPushNodes));

	queue<PosDirPair>Q;
	PosDirPair pos_dir_pair;
	pos_dir_pair.row = gBoxPos[0];
	pos_dir_pair.col = gBoxPos[1];
	pos_dir_pair.dir_from_pre = 255;
	Q.push(pos_dir_pair);
	int people_x = gPeoplePos[0];
	int people_y = gPeoplePos[1];
	int box_x, box_y, dir_from_pre, box_next_x, box_next_y, people_next_x, people_next_y;

	while (!Q.empty()){
		pos_dir_pair = Q.front();
		Q.pop();
		box_x = pos_dir_pair.row;
		box_y = pos_dir_pair.col;
		dir_from_pre = pos_dir_pair.dir_from_pre;

		if (box_x == gTargetPos[0] && box_y == gTargetPos[1]){

			SetNodeStack();
			MoveBox();
			printf("\n\n");
			return;
		}

		if (dir_from_pre != 255){
			people_x = box_x - gMoveInc[dir_from_pre][0];
			people_y = box_y - gMoveInc[dir_from_pre][1];
		}
		else{
			people_x = gPeoplePos[0];
			people_y = gPeoplePos[1];
		}

		for (int i = 1; i <= 4; i++){
			//初始的 dir不合法,为 255

			box_next_x = box_x + gMoveInc[i][0];
			box_next_y = box_y + gMoveInc[i][1];

			//pre_row 不是0,说明 点box_next_x, box_next_y 已经从i方向被进入过
			if (gCastle[box_next_x][box_next_y] == ‘#‘ || gPushNodes[box_next_x][box_next_y][i].pre_row){
				continue;
			}

			people_next_x = box_x - gMoveInc[i][0];
			people_next_y = box_y - gMoveInc[i][1];

			if (! CanPushFromPos(people_next_x, people_next_y, people_x, people_y, box_x, box_y)){
				continue;
			}

			gPushNodes[box_next_x][box_next_y][i].pre_row = box_x;
			gPushNodes[box_next_x][box_next_y][i].pre_col = box_y;

			//记录下来转弯的点的转弯之前的方向
			if (gPushNodes[box_x][box_y][i].pre_row == 0){
				gPushNodes[box_x][box_y][i].pre_dir = dir_from_pre;
			}

			pos_dir_pair.SetInfo(box_next_x, box_next_y, i);
			Q.push(pos_dir_pair);
		}
	}
	printf("Impossible.\n\n");
}

int main(){
	int cases = 1;
	while (true){
		scanf("%d %d", &gRow, &gCol);
		if (gRow == 0){
			break;
		}
		Input();
		Solve(cases ++);
	}

	return 0;
}
时间: 2024-10-14 23:23:06

poj_1475 BFS+BFS的相关文章

hdu1254 推箱子 搜索水题(bfs+bfs)

题意就不多说了 我使用bfs+bfs做的      听说bfs+dfs也能做   我觉得都差不多     我就说一下bfs+bfs 注意:箱子走过的地方还能再走   但从同一方向过来的就不能再走了    所以  标记时  得同时记录箱子和方向    方向可以根据人的位置来判断 箱子能往某一方向推的两个条件是: 目的地是空的    人能推动及人能到达要推的地方 然后按照一般广搜做就行 #include<stdio.h> #include<string.h> #include<q

hdu1254推箱子 (BFS+BFS+状态压缩)

推箱子 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5089 Accepted Submission(s): 1421 Problem Description 推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运工,搬运工的工作就是把箱子推到指定的位置,注意,搬运工只能推箱子而不能拉箱子,因此如果箱

hdu 1226 BFS + bfs记录路径

http://acm.hdu.edu.cn/showproblem.php?pid=1226 为了省空间,可以用vis数组初始化的时候初始化为-1, 发现一个BFS容易错的地方 开始一直WA在这里:就是我int tp=q.front();之后马上q.pop():了,然后才去判断是不是符合条件以break,这样就不能根据q.empty()==1认为没有找到ans 因为这里WA了 其实也可以vis[0] == -1来判断 比较不理解的是 当n==0的时候 %n==0的时候怎么处理 //#pragma

hdu - 1254 推箱子 (bfs+bfs)

http://acm.hdu.edu.cn/showproblem.php?pid=1254 题目意思很简单,只要思路对就好. 首先考虑搬运工能否到达推箱子的那个点,这个可以根据箱子前进方向得出搬运工需要到达的目的地,用另一个bfs判断,然后就类似两个点的bfs那样用一个数组标记状态, 需要注意箱子在边上的情况. 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 using namespace std;

hrbust/哈理工oj 1617 回家【BFS+BFS】

回家 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 35(9 users) Total Accepted: 10(8 users) Rating: Special Judge: No Description 寒假里,大家经常会遇上同学聚会,ikki也不例外. ikki所在的城市可以看成是一个正方形的布局,分为n*n个小方格区域.ikki每次聚会的场所都在城市的西北角,即方格 (1,1)表示的位置,而家位于城市的东南角,即(n,n)

HDU 3313 Key Vertex(BFS+BFS) 求S点到T点路径的关键点

Key Vertex Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1349    Accepted Submission(s): 307 Problem Description You need walking from vertex S to vertex T in a graph. If you remove one vert

poj 3126 Prime Path (bfs)

Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13813   Accepted: 7796 Description The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-dig

BFS简单题套路_Codevs 1215 迷宫

BFS 简单题套路 1. 遇到迷宫之类的简单题,有什么行走方向的,先写下面的 声明 const int maxn = 20; struct Status { int r, c; Status(int r = 0, int c = 0) : r(r), c(c) {} // int DIR; }; int N; //迷宫数量 int W; //迷宫宽度 char map[maxn][maxn]; //地图 //方向 : 分别代表 上.右.下.左向量 int dir[4][2] = { {-1, 0

BFS、双向BFS和A*

BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个终点.按骑士的走法(走日字),从起点到终点的最少移动多少次 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2RraXJjaGhvZmY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/g