Description
題解:
按位考慮,假設當前考慮到第x位.
f[i]表示從i到n第x位是1的機率.
枚舉i的後繼節點j
如果i到j的邊第x位是1,那f[i]+=1/d[i]*(1-f[j]);
如果i到j的邊第x為是0,那f[i]+=1/d[i]*f[j];
f[n]=0;
這樣對於每個i都可以列出一個方程,高斯消元即可.
每次把f[1]*(2^x)累加進答案即可.
代碼:
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#define N 510 #define M 10010using namespace std;double ans,a[N][N],p[N];int n,m,cnt,x,y,v,d[N],bin[N],point[N],next[M<<1];struct use{ int st,en,v;}e[M<<1];int read(){ int x(0);char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x;}void add(int x,int y,int v){ d[x]++; next[++cnt]=point[x];point[x]=cnt; e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;}void gauss(){ for (int i=1;i<=n;i++){ int k=i; for (int j=i+1;j<=n;j++) if (fabs(a[j][i])>fabs(a[k][i])) k=j; if (k!=i) for (int j=1;j<=n+1;j++) swap(a[i][j],a[k][j]); for (int j=i+1;j<=n;j++){ double temp=-a[j][i]/a[i][i]; for (int x=1;x<=n+1;x++) a[j][x]+=a[i][x]*temp;} } for (int i=n;i>=1;i--){ for (int j=i+1;j<=n;j++) a[i][n+1]-=a[i][j]*p[j]; p[i]=a[i][n+1]/a[i][i]; }}int main(){ n=read();m=read(); for (int i=1;i<=m;i++){ x=read();y=read();v=read(); add(x,y,v);if (x!=y)add(y,x,v); } bin[0]=1; for (int i=1;i<=30;i++) bin[i]=bin[i-1]*2; for (int k=0;k<=30;k++){ memset(a,0,sizeof(a)); for (int i=1;i<n;i++){ double temp=1.0/d[i]; a[i][i]=1.0; for (int j=point[i];j;j=next[j]) if (e[j].v&bin[k]) a[i][e[j].en]+=temp,a[i][n+1]+=temp; else a[i][e[j].en]-=temp; } a[n][n]=1.0;gauss(); ans+=p[1]*bin[k]; } printf("%.3f\n",ans);}