遇到位运算,还是一位一位来。假设考虑二进制第k位,那么
令f[i]表示以到达i时,第i位存在的期望,那么对于所有与i相连的j,如果(i,j)的第k位为1,那么f[i]+=(1-f[j])/i的入度,否则f[i]+=f[j]/i的入度。
这样看起来有n个方程,但是有一个是没用的,随便去掉一个。然后实际上令从n到1是等价的,只需要让f[n]=0即可。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define eps 1e-10 #define N 105 #define M 20005 using namespace std; int n,m,tot,bin[35],etr[N],fst[N],pnt[M],len[M],nxt[M]; double a[N][N]; void add(int x,int y,int z){ etr[y]++; pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot; } void gas(){ int i,j,k; for (i=1; i<=n; i++){ for (j=i; j<=n; j++) if (a[j][i]) break; if (j>n) continue; if (i!=j) swap(a[i],a[j]); for (k=i+1; k<=n; k++) if (fabs(a[k][i])>eps){ double x=a[k][i]/a[i][i]; for (j=n+1; j>=i; j--) a[k][j]-=x*a[i][j]; } } for (i=n; i; i--){ for (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); int i,x,p,mx=0; for (i=1; i<=m; i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); if (x!=y) add(y,x,z); mx=max(mx,z); } bin[0]=1; for (i=1; i<=30; i++) bin[i]=bin[i-1]<<1; double ans=0; for (i=0; bin[i]<=mx; i++){ memset(a,0,sizeof(a)); for (x=1; x<=n; x++){ a[x][x]=1; for (p=fst[x]; p; p=nxt[p]){ int y=pnt[p]; if (len[p]&bin[i]){ a[x][y]+=1.0/etr[x]; a[x][n+1]+=1.0/etr[x]; } else a[x][y]-=1.0/etr[x]; } } for (x=1; x<=n+1; x++) a[n][x]=0; a[n][n]=1; gas(); ans+=a[1][n+1]*bin[i]; } printf("%.3f\n",ans); return 0; }
by lych
2016.3.7