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; }