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



posted @ 2017-07-19 15:05  mfmdaoyou  阅读(128)  评论(0编辑  收藏  举报