POJ1475 推箱子---模块化思想
自古逢秋悲寂寥,我言秋日胜春朝。
晴空一鹤排云上,便引诗情到碧霄。 ——刘禹锡
题目:推箱子
网址:http://poj.org/problem?id=1475
推箱子游戏相信大家都不陌生,在本题中,你将控制一个人把1个箱子到目的地。
给定一张N行M列的地图,用字符”.”表示空地,字符”#”表示墙,字符”S”表示人的起始位置,字符”B”表示箱子的起始位置,字符”T”表示箱子的目标位置。
求一种移动方案,使箱子移动的次数最少,在此基础上再让人移动的总步数最少。
方案中使用大写的“EWSN”(东西南北)表示箱子的移动,使用小写的“ewsn”(东西南北)表示人的移动。
输入格式
输入包含多个测试用例。
对于每个测试用例,第一行包括两个整数N,M。
接下来N行,每行包括M个字符,用以描绘整个N行M列的地图。
当样例为N=0,M=0时,表示输入终止,且该样例无需处理。
输出格式
对于每个测试用例,第一行输出”Maze #”+测试用例的序号。
第二行输入一个字符串,表示推箱子的总体移动过程,若无解,则输出”Impossible.”。
每个测试用例输出结束后输出一个空行。
若有多条路线满足题目要求,则按照N、S、W、E的顺序优先选择箱子的移动方向(即先上下推,再左右推)。
在此前提下,再按照n、s、w、e的顺序优先选择人的移动方向(即先上下动,再左右动)。
数据范围
1≤N,M≤20
输入样例:
1 7
SB....T
1 7
SB..#.T
7 11
###########
#T##......#
#.#.#..####
#....B....#
#.######..#
#.....S...#
###########
8 4
....
.##.
.#..
.#..
.#.B
.##S
....
###T
0 0
输出样例:
Maze #1
EEEEE
Maze #2
Impossible.
Maze #3
eennwwWWWWeeeeeesswwwwwwwnNN
Maze #4
swwwnnnnnneeesssSSS
这道题有点难,我们不妨可以这样考虑进行假设:
- 若没有箱子,我们可以使用广搜求出人到任意一点的最短距离;
题意明确要求先保证箱子步数最小,再保证人走的路程最短,并要给出具体方案;
先考虑如何保证箱子步数最小,或者说如何求解这个最小值呢?
考虑状态(box_x, box_y, man_x, man_y),对于该状态进行广度优先搜索即可。
我们考虑,请试想:该状态扩展时,会扩展出什么呢?箱子显然不可能向任意方向扩展,只有当人在箱子的一侧,将其“向前”推到符合题意的位置(无障碍),进行一次扩展操作;人的扩展可以枚举四个方向,每次扩展到没有障碍的位置时,将新状态放于队尾进行扩展。
这样,当箱子处于目标位置即为最小值了。
你做错了! !
还记得广度优先搜索满足什么性质吗?单调性。
那么,队列中什么满足单调性呢?状态满足单调性。那么,我们刚刚的做法,实际上是以总步数作为关键字,总步数单调!
而实际上题目要求箱子移动步数最优的前提下再保证人步数最小值。换言之,箱子移动步数是第一关键字,而在此满足最优的情况下,人作为第二关键表示在状态中了。
那么,对于每个状态,我们只能定义关于箱子的位置,而并不能带上人的坐标。
对于人走了多少步,我们可以在对其中进行BFS扩展;
总结:对于推箱子这个问题,其实是箱子走迷宫问题,状态的每一次扩展时所需要的人最少步数,恰又是一个BFS。
大的BFS套着一个BFS,这便是所谓的“双重BFS”!
其实,不管题目有多么复杂,如果每次考虑问题都先整体去考虑,对于细节的求解假定它是可求的,那么,当大框架大部署确定后,问题便一目了然,无论是算法设计还是代码实现。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<queue>
#define pii pair <int , int>
//To simplify the questions, we prefer to use pair and make first -> x, second -> y.
#define x first
#define y second
using namespace std;
struct rec
{
int x, y, dir;
} man, box, tg;
//tg -> target
const int MAX_size = 20 + 10;
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
const char cdir[5] = {'N', 'S', 'W', 'E', '\0'}, ddir[5] = {'n', 's', 'w', 'e', '\0'}; //up 0 down 1 left 2 right 3
queue <char> ans;
bool book[MAX_size][MAX_size][4];
bool mat[MAX_size][MAX_size];
char map[MAX_size][MAX_size];
int n, m;
int d[MAX_size][MAX_size], d_man[MAX_size][MAX_size][4], f_box[MAX_size][MAX_size][4], d_box[MAX_size][MAX_size][4];
int f_man[MAX_size][MAX_size];
void init()
{
memset(f_man, -1, sizeof(f_man));
memset(f_box, -1, sizeof(f_box));
memset(d_man, -1, sizeof(d_man));
memset(d_box, -1, sizeof(d_box));
memset(mat, false, sizeof(mat));
memset(book, false, sizeof(book));
for(int i = 1; i <= n; ++ i)
{
for(int j = 1; j <= m; ++ j)
{
if(map[i][j] == 'S')man.x = i, man.y = j;
else if(map[i][j] == 'B')box.x = i, box.y = j;
else if(map[i][j] == 'T')tg.x = i, tg.y = j, tg.dir = -1;
}
}
return;
}
bool valid(int x, int y)
{
if(x < 1 || x > n || y < 1 || y > m || map[x][y] == '#') return 0;
return 1;
}
int expand(pii st, pii ed, stack <char> &s)
{
queue <pii> Q;
while(!s.empty()) s.pop();
while(!Q.empty()) Q.pop();
if(st.x == ed.x && st.y == ed.y) return 0;
Q.push(st);
mat[st.x][st.y] = true;
d[st.x][st.y] = 0;
while(!Q.empty())
{
pii now = Q.front(), next;
Q.pop();
for(int k = 0; k < 4; ++ k)
{
next = make_pair(now.x + dx[k], now.y + dy[k]);
if(!valid(next.x, next.y) || mat[next.x][next.y]) continue;
f_man[next.x][next.y] = k;
mat[next.x][next.y] = true;
d[next.x][next.y] = d[now.x][now.y] + 1;
if(next.x == ed.x && next.y == ed.y)
{
int prev_x = next.x, prev_y = next.y, tmp_1, tmp_2;
while(!(prev_x == st.x && prev_y == st.y))
{
s.push(ddir[f_man[prev_x][prev_y]]);
tmp_1 = prev_x - dx[f_man[prev_x][prev_y]];
tmp_2 = prev_y - dy[f_man[prev_x][prev_y]];
prev_x = tmp_1, prev_y = tmp_2;
}
return d[next.x][next.y];
}
Q.push(next);
}
}
return -1;
}
void _print(int x, int y, int dir)
{
stack <char> s;
if(x == box.x && y == box.y && f_box[x][y][dir] == -1)
{
mat[box.x][box.y] = true;
expand(make_pair(man.x, man.y), make_pair(box.x - dx[dir], box.y - dy[dir]), s);
memset(mat, false, sizeof(mat));
while(!s.empty())
{
ans.push(s.top());
s.pop();
}
return;
}
int prev_dir = f_box[x][y][dir], prev_x = x - (dx[dir] + dx[prev_dir]), prev_y = y - dy[dir] - dy[prev_dir];
_print(x - dx[dir], y - dy[dir], prev_dir);
mat[x - dx[dir]][y - dy[dir]] = true;
expand(make_pair(prev_x, prev_y), make_pair(x - (dx[dir] * 2), y - (dy[dir] * 2)), s);
memset(mat, false, sizeof(mat));
while(!s.empty())
{
ans.push(s.top());
s.pop();
}
ans.push(cdir[dir]);
return;
}
bool bfs()
{
queue <rec> Q;
stack <char> s;
while(!Q.empty()) Q.pop();
int k;
for(k = 0; k < 4; ++ k)
{
int &num = d_box[box.x][box.y][k], &cnt = d_man[box.x][box.y][k];
if(!valid(box.x - dx[k], box.y - dy[k])) continue;
mat[box.x][box.y] = true;
cnt = expand(make_pair(man.x, man.y), make_pair(box.x - dx[k], box.y - dy[k]), s);
memset(mat, false, sizeof(mat));
if(cnt == -1) continue;
Q.push(rec {box.x, box.y, k});
book[box.x][box.y][k] = true;
num = 0;
}
while(!Q.empty())
{
rec now = Q.front(), next;
Q.pop();
for(k = 0; k < 4; ++ k)
{
next.x = now.x + dx[k];
next.y = now.y + dy[k];
next.dir = k;
if(!valid(next.x, next.y)) continue;
int &num = d_box[next.x][next.y][k], &cnt = d_man[next.x][next.y][k] , tmp;
mat[now.x][now.y] = true;
tmp = expand(make_pair(now.x - dx[now.dir], now.y - dy[now.dir]), make_pair(now.x - dx[k], now.y - dy[k]), s);
memset(mat, false, sizeof(mat));
if(tmp == -1) continue;
if(book[next.x][next.y][next.dir])
{
if(num >= d_box[now.x][now.y][now.dir] + 1 && cnt > tmp + d_man[now.x][now.y][now.dir])
{
num = d_box[now.x][now.y][now.dir] + 1;
cnt = d_man[now.x][now.y][now.dir] + tmp;
f_box[next.x][next.y][k] = now.dir;
}
continue;
}
book[next.x][next.y][k] = true;
f_box[next.x][next.y][next.dir] = now.dir;
num = d_box[now.x][now.y][now.dir] + 1;
cnt = d_man[now.x][now.y][now.dir] + tmp;
if(next.x == tg.x && next.y == tg.y)
{
if(tg.dir == -1)
tg.dir = next.dir;
else
{
if(num > d_box[tg.x][tg.y][tg.dir])
{
_print(tg.x, tg.y, tg.dir);
return true;
}
else if(cnt < d_man[tg.x][tg.y][tg.dir]) tg.dir = next.dir;
}
}
Q.push(next);
}
}
if(tg.dir != -1)
{
_print(tg.x, tg.y, tg.dir);
return true;
}
return false;
}
int main()
{
int T = 1;
while(scanf("%d %d", &n, &m) == 2 && n && m)
{
printf("Maze #%d\n", (T ++));
for(int i = 1; i <= n; ++ i)
{
scanf("%s", map[i] + 1);
}
init();
if(bfs())
{
while(!ans.empty())
{
printf("%c", ans.front());
ans.pop();
}
puts("");
}
else puts("Impossible.");
puts("");
}
return 0;
}
POJ1475 推箱子---模块化思想的更多相关文章
- 推箱子 Sokoban(华中农业比赛)
点这里 打开题目链接 点击打开链接 题目就是我们玩过的推箱子: 一顿暴力广搜:加状态标记.状态压缩需要用到一个类似于康拓的思想来压缩:所以容易TLE,搜索就是用一个int型的数字来表示一个状态, ...
- hdu 1254 推箱子(嵌套搜索,bfs中有dfs)
推箱子 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- OC推箱子
#include<stdio.h> #include<stdlib.h> int main(void) { char sr;//存储用户输入的指令 //绘制地图 char a[ ...
- c语言游戏推箱子
前两天做了推箱子小游戏,看似简单的一个小游戏背后却 有巨大的秘密,这秘密就是一大堆逻辑. 自从学习了函数过后,的确是解决了很多问题,而且调用很方便,尽管我现在都不是很会调用. 写完一个函数,准备测试一 ...
- JavaScript写一个小乌龟推箱子游戏
推箱子游戏是老游戏了, 网上有各种各样的版本, 说下推箱子游戏的简单实现,以及我找到的一些参考视频和实例: 推箱子游戏的在线DEMO : 打开 如下是效果图: 这个拖箱子游戏做了移动端的适配, 我使用 ...
- 用C#制作推箱子小游戏
思路分析: 一.制作一个地图 二.地图中放置墙.箱子.人.目标等 三.让小人动起来完成推箱子动作 游戏制作: 1.按照上述地图制作一个地图 (12行×13列) 地图可以看做是行和列组成的,即可以看做 ...
- hdu.1254.推箱子(bfs + 优先队列)
推箱子 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submis ...
- [游戏模版17] Win32 推箱子 迷宫
>_<:Here introduce a simple game: >_<:resource >_<:only can push a box and finally ...
- [转]Flash ActionScript2.0面向对象游戏开发-推箱子
本文转自:http://www.alixixi.com/Dev/W3C/Flash/2007/2007070868666.html 概述: Flash ActionScript2.0是一种面向对向的编 ...
随机推荐
- 并查集例题02.带权并查集(poj1182)
Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底 ...
- Python学习笔记:函数详解(下)
本文介绍:高阶函数,嵌套函数,以及由前面两个组成的装饰器 一.高阶函数:以下两种情况都是高阶函数 1.将函数名当成参数传递给另外一个函数(作用:不修改被传递函数源代码就可以添加新功能): impo ...
- 1062 Talent and Virtue (25分)(水)
About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about ...
- php 直接跳出嵌套循环
break 结束当前 for,foreach,while,do-while 或者 switch 结构的执行. break 可以接受一个可选的数字参数来决定跳出几重循环. <?php $arr = ...
- 一个lock锁就可以分出低中高水平的程序员对问题的处置方式
说到lock锁,我相信在座的各位没有不会用的,而且还知道怎么用不会出错,但让他们聊一聊为什么可以锁住,都说人以群分,大概就有了下面低中高水平的三类人吧. 第一类人 将lock对象定义成static,这 ...
- leetcode c++做题思路和题解(1)——常规题总结
常规题总结 0. 目录 两数之和 1. 两数之和 耗时4ms(98.82%),内存6.2m. 两数之和--寻找中值向两边扩散法 1.1 思路 思路很简单,就是先找数组中target/2的前后两个值,然 ...
- tf.nn.sigmoid_cross_entropy_with_logits 分类
tf.nn.sigmoid_cross_entropy_with_logits(_sentinel=None,,labels=None,logits=None,name=None) logits和la ...
- python 自动生成model 文件 案例分析
生成方式 Python中想要自动生成 model文件可以通过 sqlacodegen这个命令来生成对应的model文件 sqlacodegen 你可以通过pip去安装: pip install sql ...
- java web之Filter详解
java web之Filter详解 2012-10-20 0 个评论 作者:chenshufei2 收藏 我要投稿 .概念: Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,W ...
- 掉了10根头发都无法解决的数学题,python帮你完美解答
本来这个周末过得开开心心,结果为了解一道数学题薅掉了一把头发...整整10根! 而且还是一道小学数学题!!! 到底是什么题呢?大家看看吧 这不就是一道逻辑题嘛! 先假如丁错,则甲乙丙对,此时最小的ab ...