解题思路
拆位高斯消元求概率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;
}