1. 程式人生 > >BZOJ2337 [HNOI2011]XOR和路徑 【概率dp + 高斯消元】

BZOJ2337 [HNOI2011]XOR和路徑 【概率dp + 高斯消元】

但是 ++ clu alt HA exit rep 等於 找到

題目

技術分享圖片

題解

突然get到這樣路徑期望的題目八成是高斯消元
因為路徑上的dp往往具有後效性,這就形成了一個方程組

對於本題來說,直接對權值dp很難找到突破口
但是由於異或是位獨立的,我們考慮求出每一位的期望

\(f[i]\)為從節點\(i\)出發到達N的期望值
\(f[i] = \frac{f[j]}{degree[i]} + \frac{1 - f[k]}{degree[i]} [edge(i,j) = 0,edge(i,k) = 1]\)
因為如果出邊權值為0,異或之後值不變,等於\(f[j]\)的值,
如果權值為1,異或後取反,等於\(1-f[k]\)
同時\(f[n] = 0\)
列出式子後就是一個n元方程組

最後要註意自環只算該點的一條邊

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define eps 1e-9
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
using namespace std;
const int maxn = 105
,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - 48; c = getchar();} return out * flag; } int
h[maxn],ne = 2; double de[maxn]; struct EDGE{int to,nxt,w;}ed[maxm]; inline void build(int u,int v,int w){ ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++; if (u != v){ ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++; de[u] += 1,de[v] += 1; } else de[u] += 1; } int n,m,p; double A[maxn][maxn],ans; void gause(){ for (int i = 1; i <= n; i++){ int j = i; for (int k = i + 1; k <= n; k++) if (fabs(A[k][i]) > fabs(A[j][i])) j = k; if (fabs(A[j][i]) < eps) exit(0); double t = A[j][i]; for (int k = i; k <= n + 1; k++) swap(A[i][k],A[j][k]),A[i][k] /= t; for (j = i + 1; j <= n; j++){ if (fabs(A[j][i]) > eps){ t = A[j][i]; for (int k = i; k <= n + 1; k++) A[j][k] -= A[i][k] * t; } } } for (int i = n; i; i--){ for (int j = n; j > i; j--) A[i][n + 1] -= A[i][j] * A[j][n + 1]; A[i][n + 1] /= A[i][i]; } } void solve(){ 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] = de[i]; Redge(i){ if ((ed[k].w >> p) & 1){ A[i][n + 1] += 1.0; A[i][ed[k].to] += 1.0; }else A[i][ed[k].to] -= 1.0; } } A[n][n] = 1; gause(); ans += (1 << p) * A[1][n + 1]; } int main(){ n = read(); m = read(); int a,b,w; for (int i = 1; i <= m; i++){ a = read(); b = read(); w = read(); build(a,b,w); } for (p = 0; (1 << p) <= INF; p++) solve(); printf("%.3lf\n",ans); return 0; }

BZOJ2337 [HNOI2011]XOR和路徑 【概率dp + 高斯消元】