• 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
    ", 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
    ", 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("
    
    ");
    			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.
    
    ");
    }
    
    int main(){
    	int cases = 1;
    	while (true){
    		scanf("%d %d", &gRow, &gCol);
    		if (gRow == 0){
    			break;
    		}
    		Input();
    		Solve(cases ++);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    Python接口测试学习笔记(五)
    Python接口测试学习笔记(四)
    Python接口测试学习笔记(三)
    Python接口测试学习笔记(二)
    Caused by: java.sql.SQLException: Unable to load authentication plugin 'caching_sha2_password'.
    Linux虚拟机安装MySQL8.0数据库
    剑指offer题解02-10
    Git使用的常用命令
    使用IDEA整合SSM框架
    IntelliJ IDEA 连接数据库 详细过程
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4767758.html
Copyright © 2020-2023  润新知