推箱子

题面

推箱子游戏相信大家都不陌生,在本题中,你将控制一个人把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;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/12892970.html