Description
看到是异或考虑按位来做,枚举二进制每一位,设f[i]表示从i到n的这一位为1的概率(虽然我也不知道为什么那么多博客说是期望)。然后显然f[n]=0(没有边可以走),
f[i]=∑f[j]*1/d[i](边权这一位为0)+(1-f[j])*1/d[i](边权这一位为1)
最后累计加上第一个点对答案的贡献即期望ans+=f[i]*(1<<i)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,head[105],tot,d[105];
double a[105][105];
struct edge{int v,next,w;}e[30020];
void adde(int a,int b,int c){
e[tot].v=b,e[tot].next=head[a],e[tot].w=c;
head[a]=tot++;
}
void solve(){
for(int now,i=1;i<=n;i++){
for(now=i;now<=n;now++)if(a[now][i])break;
if(now>n)continue;
if(now^i)for(int j=1;j<=n+1;j++)swap(a[i][j],a[now][j]);
double t=a[i][i];
for(int j=1;j<=n+1;j++)a[i][j]/=t;
for(int j=1;j<=n;j++)if(j!=i&&a[j][i]){
t=a[j][i];
for(int k=1;k<=n+1;k++)a[j][k]-=t*a[i][k];
}
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int x,b,c,i=1;i<=m;i++){
scanf("%d%d%d",&x,&b,&c);
adde(x,b,c);d[x]++;
if(x^b)adde(b,x,c),d[b]++;
}
double ans=0;
for(int j=0;j<=31;j++){
memset(a,0,sizeof(a));
for(int u=1;u<n;u++){
a[u][u]=1;
for(int v,k=head[u];k!=-1;k=e[k].next){
v=e[k].v;
if((e[k].w>>j)&1)a[u][n+1]+=1.0/d[u],a[u][v]+=1.0/d[u];
else a[u][v]-=1.0/d[u];
}
}
solve();
ans+=a[1][n+1]*(1<<j);
}
printf("%.3lf",ans);
return 0;
}