BZOJ 2337 XOR和路径

题意:

给出一个无向图(N个点,M条边),有自环,有重边,问从点1到点N路径异或和的期望值。

 

题解:

0.对二进制每一位考虑

1.定义dp[u]表示u到n的这一位为1的概率。

2.如果u到v这条边这位为1,那么dp[u] += (1-dp[v]) / deg[u]

 如果u到v这条边这位为0,那么dp[u] += dp[v] / deg[u]

3.根据以上的式子可以列出多个方程利用高斯消元就好啦O(∩_∩)O~

 

代码:

/**************************************************************
    Problem: 2337
    User: Xgtao
    Language: C++
    Result: Accepted
    Time:172 ms
    Memory:4116 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
const int N = 1e5 + 7;;
int ecnt, deg[N], n, m;
double a[110][110];
 
struct edge {
    int u, v, w;
}e[N<<1];
 
void adde (int u, int v, int w) {
    e[ecnt].u = u;
    e[ecnt].v = v;
    e[ecnt].w = w;
    ++deg[u], ++ecnt;
}
 
void Guass () {
    for (int i = 1; i <= n; ++i) {
        for (int j = i; j <= n; ++j) {
            if (a[j][i] == 0) continue;
            for (int k = 1; k <= n + 1; ++k) {
                swap (a[i][k], a[j][k]);
            }
            for (int k = 1; k <= n + 1; ++k) {
                if (k != i) a[i][k] /= a[i][i];
            }
            a[i][i] = 1;
            break;
        }
        if (a[i][i] == 0) continue;
        for (int j = 1; j <= n; ++j) {
            if (i == j || a[j][i] == 0) continue;
            double T = a[j][i];
            for (int k = i; k <= n + 1; ++k) {
                a[j][k] -= T * a[i][k];
            }
        }
    }
}
 
void build (int p) {
    memset (a, 0, sizeof a);
    for (int i = 1; i <= n; ++i) a[i][i] = 1;
    for (int i = 0; i < ecnt; ++i) {
        int u = e[i].u, v = e[i].v;
        if (u == n) continue;
        if (e[i].w >> p & 1) {
            a[u][v] += 1.0 / deg[u];
            a[u][n + 1] += 1.0 / deg[u];
        }
        else a[u][v] -= 1.0 / deg[u];
    }
}
 
int main () {
    scanf ("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        scanf ("%d%d%d", &u, &v, &w);
        adde (u, v, w);
        if (u != v) adde (v, u, w);
    }
    double ans = 0;
    for (int i = 30; i  >= 0; --i) {
        build(i);
        Guass();
        ans += a[1][n + 1] * (1 << i);
    }
    printf ("%.3lf\n", ans);
    return 0;
}

  

posted @ 2016-10-15 15:10  xgtao  阅读(205)  评论(0编辑  收藏  举报