1 条题解
-
0
思路与算法
用26位掩码记录路径已经出现的大写字母。DFS枚举当前位置的上下左右邻居,邻居字母尚未在掩码中时才继续,进入分支把该位设1。记录最大长度,若已达到整个矩阵不同字母总数,直接结束后续搜索。
正确性说明
掩码准确表示当前路径的字母集合,所以每步扩展都不会重复字母。DFS枚举全部合法下一步,因此覆盖所有从左上出发的合法路径。路径长度即访问字母数,取最大值得到目标。矩阵不同字母总数是所有路径共同上界,一旦达到就已最优,提前停止安全。
复杂度
每层最多扩展4邻居,后续不能原路返回且最多26层,粗上界O(RS+4×3^25),实际取决于可行路径数量;不能宣称多项式。保存矩阵O(RS),递归栈O(26),掩码复制O(1)。扫描不同字母的初始化O(RS)。
易错点
限制是不能重复字母,不仅是不能重复格子。移动只能四邻接,起点固定左上。DFS的集合随分支传值,无需错误地在全局永久标记某字母。测试覆盖20×20全相同及可走满20个不同字母的边界布局。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int R, S, best, limit; vector<string> g; void dfs(int x, int y, unsigned mask, int len) { best = max(best, len); if (best == limit) return; int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1}; for (int z = 0; z < 4; ++z) { int a = x + dx[z], b = y + dy[z]; if (a >= 0 && a < R && b >= 0 && b < S) { unsigned bit = 1U << (g[a][b] - 'A'); if (!(mask & bit)) dfs(a, b, mask | bit, len + 1); if (best == limit) return; } } } int main() { cin >> R >> S; g.resize(R); unsigned all = 0; for (auto &s : g) { cin >> s; for (char c : s) all |= 1U << (c - 'A'); } limit = __builtin_popcount(all); dfs(0, 0, 1U << (g[0][0] - 'A'), 1); cout << best << '\n'; }
- 1