题意:有一个无向图,边带权,从点1开始,每次随机选择与这个点相邻的一条边走到另一个点,直到走到点n.权值为所有走过的边的异或和(若一条边经过多次则被异或多次),求权值的期望值。
思路:将每一位拆开。那么相当于边上的权值只有0,1.
由于到达n就立即停止,我们定义f[i]表示从i到达n的期望值。
那么显然f[n]=0,对于i!=n,我们列出其转移方程:
for all x near i if (Edge(x,i)==0) f[i]+=f[x]/du[i] else f[i]+=(1-f[x])/du[i].(大概是这个意思)
然后就有n-1个方程,有高斯消元求解即可。
最终的答案就是f[1]*2^i(假设当前是第i位)
将所有位的答案累加即可。
Code:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std;
typedef double f2;
#define N 110
#define M 10010
int head[N], next[M << 1], end[M << 1], len[M << 1], du[N];
void addedge(int a, int b, int _len) {
static int q = 1;
len[q] = _len;
end[q] = b;
next[q] = head[a];
head[a] = q++;
}
f2 A[N][N];
#define _abs(x) ((x)>0?(x):-(x))
void Gauss(int n) {
register int i, j, k;
f2 tmp;
for(i = 1; i <= n; ++i) {
k = i;
for(j = i + 1; j <= n; ++j)
if (_abs(A[j][i]) > _abs(A[k][i]))
k = j;
if (k != i)
for(j = i; j <= n + 1; ++j)
swap(A[i][j], A[k][j]);
for(j = i + 1; j <= n; ++j) {
tmp = -A[j][i] / A[i][i];
A[j][i] = 0;
for(k = i + 1; k <= n + 1; ++k)
A[j][k] += tmp * A[i][k];
}
}
for(i = n; i >= 1; --i) {
for(j = i + 1; j <= n; ++j)
A[i][n + 1] -= A[j][n + 1] * A[i][j];
A[i][n + 1] /= A[i][i];
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("tt.in", "r", stdin);
#endif
int n, m;
scanf("%d%d", &n, &m);
register int i, j;
int a, b, x;
for(i = 1; i <= m; ++i) {
scanf("%d%d%d", &a, &b, &x);
if (a != b) {
++du[a], ++du[b];
addedge(a, b, x);
addedge(b, a, x);
}
else {
++du[a];
addedge(a, a, x);
}
}
f2 res = 0;
for(int bit = 0; bit < 30; ++bit) {
memset(A, 0, sizeof(A));
for(i = 1; i < n; ++i) {
A[i][i] = 1;
for(j = head[i]; j; j = next[j]) {
if ((len[j] >> bit) & 1)
A[i][n + 1] += 1 / (f2)du[i], A[i][end[j]] += 1 / (f2)du[i];
else
A[i][end[j]] -= 1 / (f2)du[i];
}
}
A[n][n] = 1;
Gauss(n);
res += A[1][n + 1] * (1 << bit);
}
printf("%.3lf", res);
return 0;
}