题目大意

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

题目分析

求最短路径的搜索问题,使用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;
}

poj_1475 BFS+BFS的更多相关文章

  1. 最少步数(dfs + bfs +bfs优化)

    最少步数 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 这有一个迷宫,有0~8行和0~8列: 1,1,1,1,1,1,1,1,1 1,0,0,1,0,0,1,0,1 ...

  2. cf1037D. Valid BFS?(BFS?)

    题意 题目链接 Sol 非常妙的一道题.. 可以这样想,在BFS序中较早出现的一定是先访问的,所以把每个点连出去的边按出现的前后顺序排个序 看一下按顺序遍历出来的序列与给出的是否相同就行了 #incl ...

  3. hdu - 1254 推箱子 (bfs+bfs)

    http://acm.hdu.edu.cn/showproblem.php?pid=1254 题目意思很简单,只要思路对就好. 首先考虑搬运工能否到达推箱子的那个点,这个可以根据箱子前进方向得出搬运工 ...

  4. hdu 1226 BFS + bfs记录路径

    http://acm.hdu.edu.cn/showproblem.php? pid=1226 为了节省空间.您可以使用vis初始化数组初始化-1. 发现BFSeasy错了地方 始一直WA在这里:就是 ...

  5. HDU 4123 (2011 Asia FZU contest)(树形DP + 维护最长子序列)(bfs + 尺取法)

    题意:告诉一张带权图,不存在环,存下每个点能够到的最大的距离,就是一个长度为n的序列,然后求出最大值-最小值不大于Q的最长子序列的长度. 做法1:两步,第一步是根据图计算出这个序列,大姐头用了树形DP ...

  6. 数据结构学习笔记05图 (邻接矩阵 邻接表-->BFS DFS、最短路径)

    数据结构之图 图(Graph) 包含 一组顶点:通常用V (Vertex) 表示顶点集合 一组边:通常用E (Edge) 表示边的集合 边是顶点对:(v, w) ∈E ,其中v, w ∈ V 有向边& ...

  7. codeforces 590C C. Three States(bfs+连通块之间的最短距离)

    题目链接: C. Three States time limit per test 5 seconds memory limit per test 512 megabytes input standa ...

  8. HDU 3085 Nightmare Ⅱ 双向BFS

    题意:很好理解,然后注意几点,男的可以一秒走三步,也就是三步以内的都可以,鬼可以穿墙,但是人不可以,鬼是一次走两步 分析:我刚开始男女,鬼BFS三遍,然后最后处理答案,严重超时,然后上网看题解,发现是 ...

  9. HDU 3681 Prison Break(状态压缩dp + BFS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 前些天花时间看到的题目,但写出不来,弱弱的放弃了.没想到现在学弟居然写出这种代码来,大吃一惊附加 ...

随机推荐

  1. 【C#】解析XML

    最近在尝试用WPF搞点桌面小应用. C#中使用System.Xml.XmlDocument类对XML文件进行操作. 文档详情如下: https://msdn.microsoft.com/en-us/l ...

  2. 轻量级ORM框架Dapper应用四:使用Dapper返回多个结果集

    使用Dapper的QueryMultiple方法可以一次执行多条SQL语句,返回多个结果集,代码如下 using System; using System.Collections.Generic; u ...

  3. 基于Struts2.3.x+Spring3.2.x+Hibernate4.2.x+EasyUI1.3.4+Maven架构的示例程序

    基于Struts2.3.x+Spring3.2.x+Hibernate4.2.x+EasyUI1.3.4+Maven架构的示例程序 不知道为什么,保存的时候显示有一个连接为违禁内容,可能是…………. ...

  4. Java并发编程基础

    Java并发编程基础 1. 并发 1.1. 什么是并发? 并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互 ...

  5. hibernate中一对多多对一关系设计的理解

    1.单向多对一和双向多对一的区别? 只需要从一方获取另一方的数据时 就使用单向关联双方都需要获取对方数据时 就使用双向关系 部门--人员 使用人员时如果只需要获取对应部门信息(user.getdept ...

  6. C++ 类的隐式转换

    所谓类的隐式转换,就是将实参类型转成形参类型--如果不一致的话. 这个转换与基本类型转换不太一样,具体则是在形参类型的构造函数中使用实参类型的数据,从而构造出一个临时对象. 下面的代码,类Person ...

  7. e673. Getting Amount of Free Accelerated Image Memory

    Images in accelerated memory are much faster to draw on the screen. However, accelerated memory is t ...

  8. yasm开源汇编器分析

    https://www.google.com.hk/search?q=yasm&oq=yasm&aqs=chrome..69i57&sourceid=chrome&es ...

  9. 使用什么工具连接MySQL Server

    字符界面:命令行终端(需MySQL Client) GUI界面:Navicat.MySQL Workbench 开发语言:使用相应语言的MySQL数据库驱动包或模块连接MySQL 我一般用的是命令行, ...

  10. erlang -- ios apns provider -- erlang 实现

    os apns-apple notification server 与第三方provider的通信原理网上已有很多介绍,这里不再介绍,有想了解的大家可以去IOS官网https://developer. ...