题意:
给出一个无向图(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;
}