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

bzoj 2337 [HNOI2011]XOR和路徑【高斯消元+dp】

name 直接 ring size scanf 高斯消元 str pre hnoi

首先,我們發現,因為是無向圖,所以相連的點之間是有“依賴性”的,所以不能直接用dp求解。
因為是xor,所以按位處理,於是列線性方程組,設$ x[i] $為點i到n異或和為1的期望,因為從1到n和從n到1一樣,所以選擇倒著推,即,
if(deg[e[i].va]==0)
\[ x[u]=\sum_{v}^{v\subset son(u)}\frac{x[v]}{deg[i]} \]
else
\[ x[u]=\sum_{v}^{v\subset son(u)}\frac{1-x[v])}{deg[i]} \]
列n元n次方程組高斯消元求解即可

#include<iostream>
#include<cstdio>
#include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=105,M=100005; int n,m,h[N],cnt,in[N]; double f[N][N],ans; struct qwe { int ne,to,va; }e[M<<1]; void add(int u,int v,int w) { cnt++; in[u]++; e[cnt].ne=h[u]; e[cnt].to=v; e[cnt].va=w; h[u]=cnt; } void
gaosi() { for(int i=1;i<=n;i++) { int id=i; double mx=0.0; for(int j=i;j<=n;j++) if(fabs(f[j][i])>mx) id=j,mx=fabs(f[j][i]); if(id!=i) for(int j=1;j<=n+1;j++) swap(f[id][j],f[i][j]); double
t=f[i][i]; for(int j=1;j<=n+1;j++) f[i][j]/=t; for(int j=1;j<=n;j++) if(j!=i) { double t=f[j][i]; for(int k=1;k<=n+1;k++) f[j][k]-=t*f[i][k]; } } } int main() { scanf("%d%d",&n,&m); for (int i=1,x,y,z;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); if (x!=y) add(y,x,z); } for(int i=0;i<=30;i++) { memset(f,0,sizeof(f)); for(int u=1;u<=n-1;u++) { f[u][u]=1.0; for(int j=h[u];j;j=e[j].ne) { if(e[j].va&(1<<i)) f[u][e[j].to]+=1.0/in[u],f[u][n+1]+=1.0/in[u]; else f[u][e[j].to]-=1.0/in[u]; } } f[n][n]=1.0; gaosi(); ans+=(f[1][n+1])*(1<<i); } printf("%.3lf\n",ans); return 0; }

bzoj 2337 [HNOI2011]XOR和路徑【高斯消元+dp】