题面
推箱子游戏相信大家都不陌生,在本题中,你将控制一个人把1个箱子到目的地。
给定一张N行M列的地图,用字符”.”表示空地,字符”#”表示墙,字符”S”表示人的起始位置,字符”B”表示箱子的起始位置,字符”T”表示箱子的目标位置。
求一种移动方案,使箱子移动的次数最少,在此基础上再让人移动的总步数最少。
方案中使用大写的“EWSN”(东西南北)表示箱子的移动,使用小写的“ewsn”(东西南北)表示人的移动。
3输入格式
输入包含多个测试用例。
对于每个测试用例,第一行包括两个整数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
题解
做的时候搜了一下, 不少题解都过不了这个数据
5 7
.......
...T...
...#...
...B...
..S....
错误答案是
eenWswNNwnE
正确答案是(长度短, 箱子路径相同)
nEseNNenW
就是把局部人步数最优当成了全局人步数最优
先看题目要求的优先级
1.箱子移动步骤最少
2.人移动步骤最少
3.先上下,再左右
所以应对题目要求,我们先要使得箱子移动步骤最少
我们就把箱子广搜呗(期间保证人也可以移动到推箱子的位置)
比如 箱子从 (x, y) 到 (x + d[i][0], y + d[i][1])
那么人就必须能从 当前位置(a, b) 到 ((x - d[i][0], y - d[i][1])
这样箱子移动就最少
然后是人移动最少, 所以人位置的转移也爆搜呗
最后是先上下,再左右, 我们的d[4][2] 就先顺序写呗
d[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
你以为这就完了?
尽管我们保证了箱子路径最短,
但是箱子路径长度相同的情况下, 我们人的移动只是局部最优(就是确定箱子路径(长度相同, 路径不同)的情况下)
所以我们应当把所有的箱子路径最短的情况答案全部求出来, 排序输出第一个
细节见代码
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define fi first
#define se second
using namespace std;
typedef pair<int, int> PII;
int ma[21][21], n, m, _;
int d[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
char der[5] = "nswe";
int read()
{
char c = getchar();
while (c != '#' && c != '.' && c != 'T' && c != 'B' && c != 'S') c = getchar();
if (c == '#') return 1;
if (c == '.') return 0;
if (c == 'T') return 2;
if (c == 'B') return 3;
return 4;
}
queue<pair<PII, string>> q;
set<PII> st;
string bfs_man(PII a, PII b, PII box)
{
queue<pair<PII, string>>().swap(q);
set<PII>().swap(st);
q.push({ a, "" }); st.insert(a);
if (ma[b.fi][b.se] == 1 || ma[a.fi][a.se] == 1) return "1";
while (!q.empty())
{
string s = q.front().se;
PII cur = q.front().fi; q.pop();
if (cur == b) return s;
rep(i, 0, 3)
{
int x = cur.fi + d[i][0], y = cur.se + d[i][1];
if (x > n || x < 1 || y > m || y < 1) continue;
if (ma[x][y] == 1 || (x == box.fi && y == box.se)) continue;
if (!st.count({ x, y }))
q.push({ {x, y}, s + der[i] }), st.insert({ x, y });
}
}
return "1";
}
bool cmp(string& a, string& b)
{
if (a.size() != b.size()) return a.size() < b.size();
int i = 0;
while (i < a.size() && i < b.size() && a[i] == b[i]) ++i;
rep (j, 0, 3)
if (a[i] == der[j] || a[i] == char(der[j] ^ 32)) return true;
else if (b[i] == der[j] || b[i] == char(der[j] ^ 32)) return false;
}
queue<pair<pair<PII, PII>, string>> qu;
set <pair<PII, PII>> stt;
string bfs_box(PII b, PII r, PII t)
{
queue<pair<pair<PII, PII>, string>>().swap(qu);
set <pair<PII, PII>>().swap(stt);
qu.push({ {b, r}, "" });
vector<string> ve;
while (!qu.empty())
{
b = qu.front().fi.fi, r = qu.front().fi.se;
string s = qu.front().se; qu.pop();
if (b == t) {ve.emplace_back(s); continue;}
if (!ve.empty()) continue;
rep(i, 0, 3)
{
int x = b.fi + d[i][0], y = b.se + d[i][1];
int rx = b.fi - d[i][0], ry = b.se - d[i][1];
if (x > n || x < 1 || y > m || y < 1) continue;
if (ma[x][y] == 1) continue;
string pe = bfs_man(r, { rx, ry }, b);
if (pe == "1") continue;
string cur = s + pe + char(der[i] ^ 32);
if (!stt.count({ {x, y}, b }))
qu.push({ {{x, y}, b}, cur }), stt.insert({ {x, y}, b });
}
}
if (ve.empty()) return "";
sort(ve.begin(), ve.end(), cmp);
return ve[0];
}
int main()
{
int bx, by, tx, ty, sx, sy;
while (scanf("%d%d", &n, &m), n + m)
{
printf("Maze #%d
", ++_);
rep(i, 1, n)
rep(j, 1, m)
{
ma[i][j] = read();
if (ma[i][j] == 2) tx = i, ty = j;
else if (ma[i][j] == 3) bx = i, by = j;
else if (ma[i][j] == 4) sx = i, sy = j;
}
string ans = bfs_box({ bx, by }, { sx, sy }, { tx, ty });
if (ans == "") puts("Impossible.
");
else printf("%s
", ans.c_str());
}
return 0;
}