洛谷-P3869 [TJOI2009] 寶藏

carboxylBase發表於2024-08-02

Abstract

傳送門
本題是狀態壓縮+記憶化BFS的典型例子。

Idea

要求從出發點到終點的最短步數, BFS 自然是首選的方法,那麼,如何構造搜尋的每一個節點呢?考慮到機關的數量比較小,最多 10 種,我們可以考慮用狀態壓縮去描述機關當前的狀態,然後再記錄當前的橫縱座標,以及行走的步數即可。值得一提的是,這題需要記憶化!否則會 MLE 。

Code

#include <bits/stdc++.h>
using namespace std;

int r, c;
int mat[40][40];
struct Node
{
    int mode;
    int x, y, t;
};
Node beg_pos, end_pos;
int k;
typedef pair<int, int> pii;
pii cause[20];
pii effect[20];
int minT[40][40][3000];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cin >> r >> c;
    for (int i = 1; i < r + 1; i++)
    {
        string text;
        cin >> text;
        for (int j = 1; j < c + 1; j++)
        {
            if (text[j - 1] == '#')
            {
                mat[i][j] = 0;
            }
            else
            {
                if (text[j - 1] == 'S')
                {
                    beg_pos.x = i, beg_pos.y = j;
                }
                if (text[j - 1] == 'T')
                {
                    end_pos.x = i, end_pos.y = j;
                }
                mat[i][j] = 1;
            }
        }
    }
    cin >> k;
    for (int i = 0; i < k; i++)
    {
        cin >> cause[i].first >> cause[i].second >> effect[i].first >> effect[i].second;
    }
    beg_pos.mode = 0;
    beg_pos.t = 0;
    queue<Node> q;
    q.push(beg_pos);
    int vx[4] = {1, 0, -1, 0};
    int vy[4] = {0, 1, 0, -1};
    memset(minT, 0x3f3f3f3f, sizeof minT);
    while (!q.empty())
    {
        Node now_pos = q.front();
        q.pop();
        if (now_pos.x == end_pos.x && now_pos.y == end_pos.y)
        {
            cout << now_pos.t << endl;
            return 0;
        }
        for (int i = 0; i < 4; i++)
        {
            Node new_pos;
            new_pos.x = now_pos.x + vx[i];
            new_pos.y = now_pos.y + vy[i];
            if (new_pos.x >= r + 1 || new_pos.x <= 0 || new_pos.y >= c + 1 || new_pos.y <= 0)
            {
                continue;
            }
            int value = mat[new_pos.x][new_pos.y];
            for (int j = 0; j < k; j++)
            {
                if ((1 << j) & now_pos.mode)
                {
                    if (effect[j].first == new_pos.x && effect[j].second == new_pos.y)
                    {
                        value = 1 - value;
                    }
                }
            }
            if (value == 0)
            {
                continue;
            }
            else
            {
                new_pos.mode = now_pos.mode;
                new_pos.t = now_pos.t + 1;
                for (int j = 0; j < k; j++)
                {
                    if (cause[j].first == new_pos.x && cause[j].second == new_pos.y)
                    {
                        if ((1 << j) & new_pos.mode)
                        {
                            new_pos.mode -= (1 << j);
                        }
                        else
                        {
                            new_pos.mode += (1 << j);
                        }
                    }
                }
                if (minT[new_pos.x][new_pos.y][new_pos.mode] > new_pos.t)
                {
                    minT[new_pos.x][new_pos.y][new_pos.mode] = new_pos.t;
                }
                else
                {
                    continue;
                }
                q.push(new_pos);
            }
        }
    }
    return 0;
}