bzoj2337 XOR和路径(概率dp+高斯消元)

解题思路

  拆位高斯消元求概率dp。设f[i]表示从i异或到点n结果为1的概率,状态转移方程就是(f[i] = sum {f[v]/d[i]}(边权为0) + sum{(1-f[v])/d[i]}(边权为1))。由于给的是无向图,所以转移的顺序不好确定,可以用高斯消元解出每位从点1到点n异或值为1的概率,结果乘上对应的二进制位权即是本位的期望。

代码

const int maxn = 1e2+10;
const int maxm = 1e6+10;
int n, m, d[maxn];
vector<P> e[maxn];
double g[maxn][maxn];
void build(int x) {
    clr(g, 0);
    for (int i = 1; i<n; ++i) {
        g[i][i] = d[i];
        for (auto v : e[i]) {
            if (v.x>>x&1) g[i][v.y] += 1.0, g[i][n+1] += 1.0;
            else g[i][v.y] -= 1.0;
        }
    }
    g[n][n] = 1;
}
void gauss() {
    for (int r = 1, c = 1; c<=n; c++, r++) {
        int t = r; 
        for (int i = r+1; i<=n; ++i)
            if (fabs(g[i][c])-fabs(g[t][c])>1e-9) t = i;
        for (int i = c; i<=n+1; ++i) swap(g[t][i], g[r][i]);
        for (int i = n+1; i>=c; --i) g[r][i] /= g[r][c];
        for (int i = r+1; i<=n; ++i)
            for (int j = n+1; j>=c; --j)
                g[i][j] -= g[i][c]*g[r][j];
    }
    for (int i = n; i>1; --i)
        for (int j = i-1; j; --j) {
            g[j][n+1] -= g[i][n+1]*g[j][i];
            g[j][i] = 0;
        }
}
int main() {
    IOS;
    cin >> n >> m;
    for (int i = 1, a, b, c; i<=m; ++i) {
        cin >> a >> b >> c;
        e[a].push_back({c, b}), ++d[a];
        if (a!=b) e[b].push_back({c, a}), ++d[b];
    }
    double sum = 0;
    for (int i = 0; i<=30; ++i) {
        build(i);
        gauss();
        sum += g[1][n+1]*(1<<i);
    }
    cout << fixed << setprecision(3) << sum << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/shuitiangong/p/15379722.html