本题解受eoinlee的启发,增加注释
分析
数据范围非常小,n,m,qn,m,qn,m,q 都只有 100100100 的级别。
考虑到这点,我们可以枚举所有可能的使用颜色的情况。对于这 444 种颜色,每次搜索允许搜索路径经过其中若干种颜色的门,并检查能否在当前所允许颜色的条件下从起点走到终点。最后,计算所有可行方案经过颜色数的最小值。由于四种颜色最多只可能有 151515 种选择方案,因此每一次询问的复杂度最多只可能达到 O(15nm)O(15nm)O(15nm)。综合下来,完全可以通过本题。
注意:本题目既可以使用DFS,也可以使用BFS
另外,最好使用状态压缩进行搜索,可以很好地减小常数。
代码(使用 BFS 算法)
#include <bits/stdc++.h>
using namespace std;
// 定义常量
const int N = 1e2 + 5; // 最大网格大小
const int dx[] = {0, 1, 0, -1}; // x轴方向移动,代表东南西北
const int dy[] = {1, 0, -1, 0}; // y轴方向移动,代表东南西北
const vector<int> seq = {1, 2, 4, 8, 3, 5, 9, 6, 10, 12, 7, 11, 13, 14, 15}; // 遍历状态序列
int n, m; // 网格的行数和列数
int g[N][N][4]; // 存储每个单元格与其相邻单元格的连接状态
bool vis[N][N]; // 标记某个单元格是否被访问过
unordered_map<char, int> mp = {{'P', 0}, {'C', 1}, {'Z', 2}, {'N', 3}}; // 映射字符到连接状态
// BFS函数,用于寻找从起点到终点的路径
bool BFS(int sx, int sy, int ex, int ey, int state) {
using PII = pair<int, int>;
memset(vis, 0, sizeof vis); // 初始化访问数组
queue<PII> q;
vis[sx][sy] = true; // 标记起点为已访问
q.emplace(sx, sy); // 将起点加入队列
while (!q.empty()) {
auto [x, y] = q.front();
q.pop();
if (x == ex && y == ey) // 如果到达终点,返回true
return true;
for (int i = 0; i < 4; i++) {
int tx = x + dx[i], ty = y + dy[i];
if (tx < 1 || ty < 1 || tx > n || ty > m) continue; // 超出边界检查
if (vis[tx][ty]) continue; // 已访问检查
if ((1 << g[x][y][i]) & state) // 状态检查
q.emplace(tx, ty), vis[tx][ty] = true;
}
}
return false;
}
int main() {
ios::sync_with_stdio(false); // 加速C++输入输出
cin >> n >> m; // 输入行数和列数
char ch;
// 读入水平方向的连接状态
for (int i = 1; i <= n; i++)
for (int j = 1; j < m; j++)
cin >> ch, g[i][j][0] = g[i][j + 1][2] = mp[ch];
// 读入垂直方向的连接状态
for (int i = 1; i < n; i++)
for (int j = 1; j <= m; j++)
cin >> ch, g[i][j][1] = g[i + 1][j][3] = mp[ch];
int q; // 查询次数
cin >> q;
while (q--) {
int sx, sy, ex, ey; // 起点和终点
cin >> sx >> sy >> ex >> ey;
for (int state : seq) { // 遍历每种状态
if (BFS(sx, sy, ex, ey, state)) { // 如果找到路径
cout << __builtin_popcount(state) << endl; // 输出该状态的位数(即路径长度)
break;
}
}
}
return 0;
}
3214



被折叠的 条评论
为什么被折叠?



