zoukankan      html  css  js  c++  java
  • 推箱子

    题面

    推箱子游戏相信大家都不陌生,在本题中,你将控制一个人把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;
    }
    
  • 相关阅读:
    More Effective C++ 条款31 让函数根据一个以上的对象类型来决定如何虚化
    定点数表示方法——原码,补码,反码,移码
    More Effective C++ 条款30 Proxy classes(替身类,代理类)
    More Effective C++ 条款29 Reference counting(引用计数)
    More Effective C++ 条款28 Smart Pointers(智能指针)
    More Effective C++ 条款27 要求(禁止)对象产生与heap之中
    More Effective C++ 条款26 限制某个class所能产生的对象数量
    C/C++:对象/变量初始化相关
    More Effective C++ 条款25 将constructor和non-member function虚化
    origin作图,避免里面有Type 3 字体
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/12892970.html
Copyright © 2011-2022 走看看