设 (f(x)) 表示从 (x) 节点走到 (n) 的期望。有 $$f(x)=sum_{{x,y}}frac{f(y)oplus w(x,y)}{{
m deg}(x)}$$ 由于有后效性,无法 DP 求得。于是可以将其看作未知数,(n) 个点构成 (n) 个 (n) 元一次方程,解方程即可。
但还是不太好求,考虑期望的线性性,按位处理。
重新记 (f(x)) 表示当前位的 (x) 走到 (n) 异或和为 (1) 的概率,有 $${
m deg}(x)f(x)=sum_{w(x,y)=1}f(y)+sum_{w(x,y)=0}ig(1-f(y)ig)$$ 最后的答案为 (sumlimits_{t=1}^{32} 2^{t-1}cdot f(1))。
为了消元简便,实际求的过程中我们把方程写成 $$sum_{w(x,y)=0}f(y)-sum_{w(x,y)=1}f(y)-{
m deg}(x)f(x)=-sum_{w(x,y)=1}1$$
注意自环只用算一次。
别颓废了……抓紧时间……
#include <bits/stdc++.h>
using namespace std;
const int N=105,M=10005;
const double eps=1e-8;
struct Edge{int to,nxt,w;}e[M<<1];
int n,m,cnt,head[N],deg[N];
double ans,a[N][N];
inline void add(int u,int v,int w) {e[++cnt]=(Edge){v,head[u],w};head[u]=cnt;}
void gauss()
{
for(int i=1;i<=n;++i)
{
int t=i;
for(int j=i+1;j<=n;++j)
if(fabs(a[j][i])>fabs(a[t][i])) t=j;
for(int j=i;j<=n+1;++j) swap(a[t][j],a[i][j]);
for(int j=n+1;j>=i;--j) a[i][j]/=a[i][i];
for(int j=1;j<=n;++j)
if(i!=j)
for(int k=n+1;k>=i;--k)
a[j][k]-=a[j][i]*a[i][k];
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,d,b,c;i<=m;++i)
{
scanf("%d%d%d",&d,&b,&c);
if(d==b)
{
deg[d]++; add(d,b,c);
}
else
{
deg[d]++,deg[b]++;
add(d,b,c); add(b,d,c);
}
}
for(int k=30;~k;--k)
{
memset(a,0,sizeof(a));
for(int u=1;u<n;++u)
{
a[u][u]=-deg[u];
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to,w=(e[i].w>>k)&1;
if(w) a[u][v]-=1,a[u][n+1]-=1;
else a[u][v]+=1;
}
}
a[n][n]=1; gauss();
ans+=(1<<k)*a[1][n+1];
}
printf("%.3lf",ans);
return 0;
}