「Codeforces 1006F」Xor-Paths - 双向bfs

版权声明:禁止商业用途,如需转载请注明原文出处:https://hyp1231.github.io 或者 https://blog.csdn.net/hyp1231/article/details/81080531

建议访问原文出处,获得更佳浏览体验。
原文出处:https://hyp1231.github.io/2018/07/17/20180717-cf1006f/

题意

给定 n × m 的矩阵,以及一个整数 k
定义路径为,从 ( 1 , 1 ) 出发,只能向右 / 下方走,到达 ( n , m ) 的行走方案。
定义路径的权重为,路径经过的整数的 x o r 之和。
求权重为 k 的路径的条数。

链接

Codeforces 1006F

题解

定义从路径一端到 ( x , y ) 的某条路径上的整数的 x o r 之和为 ( x , y ) 处的状态

由于 n m 的范围均为 20 之内,考虑暴力搜索。对于每个位置,之后都有两种状态转移(向下 / 向右)。因此我们将矩阵按照 m + n 的值进行分层,如果从起点开始 b f s ,易知每次状态转移使层数加一,每一层的状态数不超过上一层的二倍,故直接 b f s 的状态数不超过 2 m + n ,但这个量级是我们不能接受的。

而考虑起点和终点的值都是唯一且确定的,我们可以从起点和终点同时采用 b f s 。因此我们规定 m + n 2 为中心层,两个 b f s 一到中心层则停止搜索,这样在中心层,如果有重合的状态则说明有合法路径。

为了记录合法路径的数目,我们需要记录某一个 b f s (这里不妨设为从起点出发的)到达状态 v a l 的路径数。在实现上,我们使用 S T L 库中的 m a p ,形成状态到路径数的映射。这样先实现从起点出发的 b f s ,得到中间层每个位置各个状态的路径数;再做另一个 b f s ,对于每个到中间层的状态,把第一个 b f s 中计算出的该状态对应的路径数加到总的 a n s 中。

这样搜索到中间层的状态数不超过 2 m + n 2 m a p 的复杂度 O ( log 2 m + n 2 ) = O ( m + n 2 log 2 ) = O ( m + n 2 ) ,总复杂度 O ( m + n 2 2 m + n 2 )

代码

#include <iostream>
#include <queue>
#include <map>

typedef long long LL;

const int N = 20;

struct State {
    int x, y;
    LL val;
    State(int x = 0, int y = 0, LL val = 0) : x(x), y(y), val(val) {}
};

int n, m, mid;
LL a[N][N], k;

// 记录中间层 状态->路径数 的映射
// 由于 x + y = (n + m) / 2,我们确定了 x 即可确定 y
// 因此 res[x][st] 代表中间层横坐标为 x 的点,状态为 st 的路径数目
std::map<LL, int> res[N << 1];

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);

    std::cin >> n >> m >> k;
    mid = (n + m - 2) >> 1;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            std::cin >> a[i][j];
        }
    }

    LL ans = 0;
    std::queue<State> que1, que2;
    que1.push(State(0, 0, a[0][0]));
    while (!que1.empty()) {
        State tmp = que1.front(); que1.pop();
        int x = tmp.x, y = tmp.y;
        LL val = tmp.val;
        if (x + y == mid) { // 到达中心线
            if (res[x].count(val)) {
                ++res[x][val];
            } else {
                res[x][val] = 1;
            }
        } else {
            if (x + 1 != n) que1.push(State(x + 1, y, val ^ a[x + 1][y]));
            if (y + 1 != m) que1.push(State(x, y + 1, val ^ a[x][y + 1]));
        }
    }

    que2.push(State(n - 1, m - 1, k));
    while (!que2.empty()) {
        State tmp = que2.front(); que2.pop();
        int x = tmp.x, y = tmp.y;
        LL val = tmp.val;
        if (x + y == mid) {
            ans += res[x][val];
        } else {
            if (x - 1 >= 0) que2.push(State(x - 1, y, val ^ a[x][y]));
            if (y - 1 >= 0) que2.push(State(x, y - 1, val ^ a[x][y]));
        }
    }

    std::cout << ans << std::endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/hyp1231/article/details/81080531