【15.4.1 Pushing Boxes】
想象您正站在一个二维的迷宫中,迷宫由是正方形的方格组成,这些方格可能被岩石阻塞,也可能没有。您可以向北,南,东或西一步移到下一个方格。这些移动被称为行走(walk)。
在一个空方格中放置了一个箱子,您可以挨着箱子站着,然后按这个方向推动这个箱子,这个箱子就可以被移动到一个临近的位置。这样的一个移动被称为推(push)。除了推以外,箱子不可能用其他的方法被移动,这就意味着如果您把箱子推到一个角落,您就永远不能再把它从角落中推出。
一个空格被标识为目标空格。您的任务就是通过一系列的行走和推把一个箱子推到目标方格中(如图15.4-1)。因为箱子非常重,您希望推的次数最少。您能编写一个程序来给出最佳的序列吗?
图15.4-1
输入
输入文件包含若干个迷宫的描述,每个迷宫描述的第一行给出两个整数r和c(都小于等于20),表示迷宫的行数和列数。
后面给出r行,每行有c个字符。每个字符描述迷宫的一个方格。一个塞满岩石的方格用一个‘#’表示,一个空方格用一个‘.’表示。你开始时站的位置用‘S’表示,箱子开始的位置用‘B’表示,目标方格用‘T’表示。
输入以两个为0的r和c结束。
输出
对输入的每个迷宫,第一行输出迷宫的编号,如样例输出。然后,如果不可能把箱子推到目标方格,输出“Impossible.”;否则,输出推的数目最小化的序列。如果存在多于一个的这样的序列,选择总的移动(行走和推)最小的序列。如果依然存在多于一个的这样的序列,那么任何一个序列都是可以被接受的。
输出序列是一个字符串,由字符N, S, E, W, n, s, e 和w组成,其中大写字母表示推,小写字母表示行走,不同的字母代表方向:北(north),南(south),东(east)和西(west)。
在每个测试用例处理后输出一个空行。
样例输入 |
样例输出 |
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 |
试题来源:ACM Southwestern European Regional Programming Contest 1997
在线测试:UVA 589,ZOJ 1249,POJ 1475
失误点
1. 搜索类流程:①复制→②模拟→③检验→④入队
为减少代码量,
宜用临时变量存储原状态(①②④)和更新后状态(②③④)
2. 看错题:
①错看成总步数最小(推箱子操作次数最小)。
②理解成只输出最小步数,用dfs来检验人的移动。
3. 判断是否越界可用#define来化简代码量
4. 代码是超时的,原因可能是应为过多字符串操作。
#include <iostream> #include <cstdio> #include <cstring> //memset #include <string> //string using namespace std; struct cor { long x, y; }; struct stb { cor b, p; long fa, s; char c; }; struct sta { cor b, p; long fa, s; string c; }; const long N=25, dop=32, M=N*N*N*N; const long d[4][3]={{-1, 0, ‘n‘}, {0, 1, ‘e‘}, {0, -1, ‘w‘}, {1, 0, ‘s‘}}; long n, m, S, hea, tai, a[N][N]; long s[N][N][N][N]; cor sb, sp, st; sta e[M]; string str; void Clr() { long x1, x2, y1, y2; for (x1=1; x1<=n; x1++) for (y1=1; y1<=m; y1++) for (x2=1; x2<=n; x2++) for (y2=1; y2<=m; y2++) s[x1][y1][x2][y2]=-1; } #define in(val) ((1 <= val.x) && (val.x <= n) && (1 <= val.y) && (val.y <= m)) bool f[N][N]; stb ge[N*N]; bool check(cor S, cor b, cor T) { cor tp, p; long i, k, hea, tai; str=""; memset(f, 0, sizeof(f)); hea=0; tai=1; ge[tai].p=S; f[S.x][S.y]=1; if (S.x == T.x && S.y == T.y) return true; f[b.x][b.y]=1; while (hea < tai) { hea++; p=ge[hea].p; for (i=0; i<4; i++) { tp.x=p.x+d[i][0]; tp.y=p.y+d[i][1]; if (in(tp) && f[tp.x][tp.y] == 0 && a[tp.x][tp.y] == 0) { tai++; ge[tai].p=tp; f[tp.x][tp.y]=1; ge[tai].fa=hea; ge[tai].c=d[i][2]; if (tp.x == T.x && tp.y == T.y) { k=tai; while (k > 1) { str=ge[k].c+str; k=ge[k].fa; } return true; } } } } return false; } long Work() { long i; cor b, p, tb, tp, T; hea=0; tai=1; e[tai].b=sb; e[tai].p=sp; s[sp.x][sp.y][sb.x][sb.y]=0; while (hea < tai) { hea++; b=e[hea].b; p=e[hea].p; for (i=0; i<4; i++) { T.x=b.x-d[i][0]; T.y=b.y-d[i][1]; if (in(T) && check(p, b, T)) { tp.x=b.x; tp.y=b.y; tb.x=b.x+d[i][0]; tb.y=b.y+d[i][1]; if (in(tb) && a[tb.x][tb.y] == 0 && s[tp.x][tp.y][tb.x][tb.y] == -1) { tai++; e[tai].b=tb; e[tai].p=tp; e[tai].fa=hea; e[tai].c=str+(char)(d[i][2]-32); e[tai].s=e[hea].s+1; s[tp.x][tp.y][tb.x][tb.y]=e[tai].s; if (tb.x == st.x && tb.y == st.y) return e[tai].s; } } } } return -1; } void print(long x) { if (x == 1) return ; print(e[x].fa); cout << e[x].c; } int main() { long i, j, ci=0;; ios::sync_with_stdio(false); // freopen("input.in", "r", stdin); cin >> n >> m; while (n > 0 && m > 0) { ci++; for (i=1; i<=n; i++) { cin >> str; str=‘ ‘+str; for (j=1; j<=m; j++) { if (str[j] == ‘#‘) { a[i][j]=1; continue; } a[i][j]=0; if (str[j] == ‘S‘) sp.x=i, sp.y=j; if (str[j] == ‘B‘) sb.x=i, sb.y=j; if (str[j] == ‘T‘) st.x=i, st.y=j; } } Clr(); S=Work(); cout << "Maze #" << ci << ‘\n‘; if (S == -1) cout << "Impossible.\n\n"; else { print(tai); cout << "\n\n"; } cin >> n >> m; } return 0; }