题目大意:给定一个无向连通图,从1出发,每次等概率沿着任意一条出边走到n为止,求路径上的边权的异或和的期望值
首先既然是位运算的问题我们的一般处理办法就是拆位,按位处理
对于每一位 令f[i]为从i节点出发到n的期望值
对于每条出边,如果这条边边权为1,那么f[x]+=f[y]/d[x] 否则f[x]+=(1-f[y])/d[x] 其中d[x]表示x的度数
特殊地,f[n]=1
由于这个图不是拓扑图,因此我们用高斯消元来解这个方程组,n个方程n个未知数(代码里写SB了- -)
解出方程后f[1]*2^k就是第k位对答案的贡献值
统计答案输出即可 注意边集不要开小 重边只要连一条
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define M 110
using namespace std;
struct abcd{
int to,f,next;
}table[M*M<<1];
int head[M],tot;
int n,m,degree[M];
long double f[M][M],a[M],ans;
void Add(int x,int y,int z)
{
degree[x]++;
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
void Gauss_Elimination()
{
int i,j,k;
for(i=1;i<n;i++)
{
k=0;
for(j=i;j<n;j++)
if( fabs(f[j][i]) > fabs(f[k][i]) )
k=j;
for(j=i;j<=n+1;j++)
swap(f[i][j],f[k][j]);
for(j=i+1;j<n;j++)
{
long double temp=-f[j][i]/f[i][i];
for(k=i;k<=n+1;k++)
f[j][k]+=f[i][k]*temp;
}
}
for(i=n-1;i;i--)
{
for(j=i+1;j<=n;j++)
f[i][n+1]-=f[i][j]*a[j];
a[i]=f[i][n+1]/f[i][i];
}
}
int main()
{
int i,j,x,y,z;
cin>>n>>m;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);
if(x!=y) Add(y,x,z);
}
for(j=0;j<=30;j++)
{
memset(f,0,sizeof f);
memset(a,0,sizeof a);
for(x=1;x<n;x++)
{
for(i=head[x];i;i=table[i].next)
if(table[i].f&(1<<j))
f[x][table[i].to]+=1,f[x][n+1]+=1;
else
f[x][table[i].to]-=1;
f[x][x]+=degree[x];
}
Gauss_Elimination();
ans+=a[1]*(1<<j);
}
cout<<fixed<<setprecision(3)<<ans<<endl;
}