BZOJ2337 [HNOI2011]XOR和路径
题意:有一个无向图。边带权,从点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; }