Time:2016.08.27
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
与游走思路有一定相似的地方
对答案的每一位进行判断
通过高斯消元解出每个点到n xor路径为1的概率
对于关于第i个点的方程来说
第i项系数为f[i][i]=-1,其他项j为
⎧⎩⎨⎪⎪⎪⎪⎪⎪0=>不存在e(i,j)或j=nf[i][j]d[j]=>存在e(i,j)且w[e]在当前位为01−f[i][j]d[j]=>存在e(i,j)且w[e]在当前位为1
然后高斯消元解就可以了,答案就是
∑30i=1ans[1]⋅2i
复杂度
O(30⋅n3)
注意自环时只加一条边而不是双向边
注意重边时要多次累加方程的系数
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define M 10005
#define eps 1e-5
using namespace std;
int n,m,tot;
struct edge{
int u,v,w,next;
}e[M<<1];
int first[105],d[105];
double f[105][105],ans[105],sum;
void add(int x,int y,int z)
{
e[++tot]=(edge){x,y,z,first[x]};first[x]=tot;
++d[x];
if (x==y) return;
e[++tot]=(edge){y,x,z,first[y]};first[y]=tot;
++d[y];
}
void gauss()
{
int t;
double p;
for (int i=1;i<n;++i)
{
t=i;
for (int j=i+1;j<=n;++j)
if (fabs(f[t][i])<fabs(f[j][i])) t=j;
if (t!=i)
for (int j=i;j<=n+1;++j)
swap(f[t][j],f[i][j]);
for (int j=i+1;j<=n;++j)
{
p=f[j][i]/f[i][i];
for (int k=i+1;k<=n+1;++k)
f[j][k]-=f[i][k]*p;
}
}
for (int i=n;i;--i)
{
p=0;
for (int j=i+1;j<=n;++j) p+=ans[j]*f[i][j];
ans[i]=(f[i][n+1]-p)/f[i][i];
}
}
main()
{
scanf("%d%d",&n,&m);
int x,y,z;
for (int i=1;i<=m;++i)
scanf("%d%d%d",&x,&y,&z),
add(x,y,z);
for (int i=30;i>=0;--i)
{
memset(f,0,sizeof(f));
for (int j=1;j<n;++j)
for (int k=first[j];k;k=e[k].next)
if (e[k].w>>i&1)
f[j][n+1]-=1.0/d[j],
f[j][e[k].v]-=1.0/d[j];
else
f[j][e[k].v]+=1.0/d[j];
for (int j=1;j<=n;++j) --f[j][j];
gauss();
sum+=ans[1]*(1<<i);
}
printf("%.3lf\n",sum);
}