1 条题解

  • 0
    @ 2026-10-26 13:21:31

    思路与算法

    用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

    信息

    ID
    1758
    时间
    1000ms
    内存
    64MiB
    难度
    普及−
    标签
    递交数
    1
    已通过
    1
    上传者