bzoj2337
高斯消元+概率dp
我好纸张
设dp[i]表示i到n异或和为1的概率,那么暴力高斯消元就行了,注意方程中n那一行要清零
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N = 105; struct edge { int u, v, w; } e[N * N]; int n, m; double ans; double deg[N], a[N][N]; void gauss_jordan() { for(int i = 1; i <= n; ++i) { int p = i; for(int j = i; j <= n; ++j) { if(fabs(a[j][i]) > fabs(a[p][i])) { p = j; } } for(int j = 1; j <= n + 1; ++j) { swap(a[i][j], a[p][j]); } double d = a[i][i]; for(int j = 1; j <= n + 1; ++j) { a[i][j] /= d; } for(int j = 1; j <= n; ++j) { if(i != j) { double d = a[j][i]; for(int k = 1; k <= n + 1; ++k) { a[j][k] -= a[i][k] * d; } } } } } void solve(int bit) { for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n + 1; ++j) { a[i][j] = 0; } } for(int i = 1; i <= n; ++i) { a[i][i] = -1; } for(int i = 1; i <= m; ++i) { int t = e[i].w >> bit & 1, u = e[i].u, v = e[i].v; if(t) { a[u][v] -= 1.0 / deg[u]; if(u != v) { a[v][u] -= 1.0 / deg[v]; } a[u][n + 1] -= 1.0 / deg[u]; if(u != v) { a[v][n + 1] -= 1.0 / deg[v]; } } else { a[u][v] += 1.0 / deg[u]; if(u != v) { a[v][u] += 1.0 / deg[v]; } } } for(int i = 1; i <= n + 1; ++i) { a[n][i] = 0; } a[n][n] = -1; gauss_jordan(); ans += a[1][n + 1] * (1 << bit); } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++i) { scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w); deg[e[i].u] += 1.0; if(e[i].u != e[i].v) { deg[e[i].v] += 1.0; } } for(int bit = 0; bit < 30; ++bit) { solve(bit); } printf("%.3f\n", ans); return 0; }