【BZOJ】2337: [HNOI2011]XOR和路径 期望+高斯消元
【题意】给定n个点m条边的带边权无向连通图(有重边和自环),在每个点随机向周围走一步,求1到n的期望路径异或值。n<=100,wi<=10^9。
【算法】期望+高斯消元
【题解】首先异或不满足期望的线性,所以考虑拆位。
对于每一个二进制位,经过边权为0仍是x,经过边权为1变成1-x(转化成减法才满足期望的线性)。
设f[x]表示点x到n的路径xor期望,f[n]=0,根据全期望公式:
$$f[i]=\sum_{j}\frac{f[j]}{out[i]}\ \ , \ \ w(i,j)=0$$
$$f[i]=\sum_{j}\frac{1-f[j]}{out[i]}\ \ , \ \ w(i,j)=1$$
因为有循环所以用高斯消元求解,复杂度O(n^3*log wi)。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int maxn=110; struct edge{int v,w,from;}e[maxn*maxn*2]; int n,m,first[maxn],tot,out[maxn]; long double a[maxn][maxn],ans; void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;out[u]++;} void gauss(){ for(int i=1;i<n;i++){ int r=i; for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>fabs(a[r][i]))r=j; if(r!=i)for(int j=i;j<=n+1;j++)swap(a[i][j],a[r][j]); for(int j=i+1;j<=n;j++) for(int k=n+1;k>=i;k--) a[j][k]-=a[j][i]/a[i][i]*a[i][k]; } for(int i=n;i>=1;i--){ for(int j=i+1;j<=n;j++)a[i][n+1]-=a[i][j]*a[j][n+1]; a[i][n+1]/=a[i][i]; } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); insert(u,v,w); if(u!=v)insert(v,u,w);// } for(int k=0;k<=30;k++){ memset(a,0,sizeof(a));// for(int x=1;x<n;x++){ for(int i=first[x];i;i=e[i].from){ if(e[i].w&(1<<k)){ a[x][e[i].v]--;// a[x][n+1]--; } else a[x][e[i].v]++; } a[x][x]-=out[x];// } a[n][n]=1; gauss(); ans+=a[1][n+1]*(1<<k); } printf("%.3Lf",ans); return 0; }
注意:
1.方程组右边是常数项。
2.自环不要重复加边。