[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=2337
[算法]
直接进行计算显然是不可做的,我们考虑按位计算答案
从低位向高位枚举,此时问题就转化为了 : 在一个联通无向图中,从1出发走到n,路径异或和为1的概率是多少
用f[i]表示从i到n路径异或和为1的概率,有状态转移方程 :
f[i] = sigma( f[j] / degree[i] ) ( w(i,j) = 0 ) + sigma( (1 - f[j]) / degree[i] ) ( w(i,j) = 1)
由于图中可能存在自环和重边,我们无法确定枚举状态的顺序,因此,需要使用高斯消元
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 110 #define MAXM 10010 #define MAXLOG 31 int i,k,u,v,w,n,m,tot; int head[MAXN],degree[MAXN]; double a[MAXN][MAXN]; double ans; struct Edge { int to,w,nxt; } e[MAXM << 1]; inline void addedge(int u,int v,int w) { tot++; e[tot] = (Edge){v,w,head[u]}; head[u] = tot; } inline void gauss() { int i,j,k,p; double rate; for (i = 1; i <= n; i++) { p = i; for (j = i + 1; j <= n; j++) { if (fabs(a[j][i]) > fabs(a[p][i])) p = j; } for (j = 1; j <= n + 1; j++) swap(a[i][j],a[p][j]); for (j = 1; j <= n; j++) { if (i == j) continue; rate = a[j][i] / a[i][i]; for (k = i; k <= n + 1; k++) a[j][k] -= a[i][k] * rate; } } } int main() { scanf("%d%d",&n,&m); for (i = 1; i <= m; i++) { scanf("%d%d%d",&u,&v,&w); if (u ^ v) { addedge(u,v,w); addedge(v,u,w); degree[u]++; degree[v]++; } else { addedge(u,v,w); degree[u]++; } } for (i = 0; i < MAXLOG; i++) { for (u = 1; u <= n; u++) { for (v = 1; v <= n + 1; v++) { a[u][v] = 0.0; } } for (u = 1; u < n; u++) { for (k = head[u]; k; k = e[k].nxt) { v = e[k].to; if (e[k].w & (1 << i)) { a[u][v] -= 1.0 / degree[u]; a[u][n + 1] -= 1.0 / degree[u]; } else a[u][v] += 1.0 / degree[u]; } a[u][u] -= 1.0; } a[n][n] = 1.0; gauss(); ans += 1.0 * a[1][n + 1] / a[1][1] * (1 << i); } printf("%.3lf ",ans); return 0; }