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;
}