Description
给定一个无向连通图,其节点编号为 1 到 N,其边的权值为非负整数。试求出一条从 1 号节点到 N 号节点的路径,使得该路径上经过的边的权值的“XOR 和”最大。该路径可以重复经过某些节点或边,当一条边在路径中出现多次时,其权值在计算“XOR 和”时也要被重复计算相应多的次数。
直接求解上述问题比较困难,于是你决定使用非完美算法。具体来说,从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下一个节点,重复这个过程,直到走到 N 号节点为止,便得到一条从 1 号节点到 N 号节点的路径。显然得到每条这样的路径的概率是不同的并且每条这样的路径的“XOR 和”也不一样。现在请你求出该算法得到的路径的“XOR 和”的期望值。
Input
从文件input.txt中读入数据,输入文件的第一行是用空格隔开的两个正整数N和M,分别表示该图的节点数和边数。紧接着的M行,每行是用空格隔开的三个非负整数u,v和w(1≤u,v≤N,0≤w≤109),表示该图的一条边(u,v),其权值为w。输入的数据保证图连通,30%的数据满足N≤30,100%的数据满足2≤N≤100,M≤10000,但是图中可能有重边或自环。
Output
输出文件 output.txt 仅包含一个实数,表示上述算法得到的路径的“XOR 和”的期望值,要求保留三位小数。(建议使用精度较高的数据类型进行计算)
Sample Input
2 2
1 1 2
1 2 3
Sample Output
2.333
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #define N (100+10) 6 using namespace std; 7 8 double eps=1e-10; 9 int dcmp(double x){if (fabs(x)<eps)return 0; return x>0?1:-1;} 10 11 struct node{int to,next,len;}edge[N*N*2]; 12 double f[N][N],ans[N],Ans; 13 int n,m,u,v,l,Ind[N]; 14 int head[N],num_edge; 15 16 void add(int u,int v,int l) 17 { 18 edge[++num_edge].to=v; 19 edge[num_edge].next=head[u]; 20 edge[num_edge].len=l; 21 head[u]=num_edge; 22 } 23 24 void Gauss() 25 { 26 for (int i=1; i<=n; ++i) 27 { 28 int num=i; 29 for (int j=i+1; j<=n; ++j) 30 if (dcmp(fabs(f[j][i])-fabs(f[num][i]))>0) num=j; 31 if (num!=i) for (int j=1; j<=n+1; ++j) swap(f[num][j],f[i][j]); 32 33 for (int j=i+1; j<=n+1; ++j) 34 if (dcmp(f[j][i])) 35 { 36 double t=f[j][i]/f[i][i]; 37 for (int k=i; k<=n+1; ++k) 38 f[j][k]-=t*f[i][k]; 39 } 40 } 41 for (int i=n; i>=1; --i) 42 { 43 for (int j=i+1; j<=n; ++j) f[i][n+1]-=f[i][j]*ans[j]; 44 ans[i]=f[i][n+1]/f[i][i]; 45 } 46 } 47 48 int main() 49 { 50 scanf("%d%d",&n,&m); 51 for (int i=1; i<=m; ++i) 52 { 53 scanf("%d%d%d",&u,&v,&l); 54 add(u,v,l); Ind[u]++; 55 if (u==v) continue; 56 add(v,u,l); Ind[v]++; 57 } 58 for (int k=0; k<=30; ++k) 59 { 60 memset(ans,0,sizeof(ans)); 61 memset(f,0,sizeof(f)); 62 for (int i=1; i<n; ++i) 63 { 64 f[i][i]=1; 65 for (int j=head[i]; j; j=edge[j].next) 66 if ((edge[j].len>>k)&1) 67 { 68 f[i][edge[j].to]+=(double)1/Ind[i]; 69 f[i][n+1]+=(double)1/Ind[i]; 70 } 71 else 72 f[i][edge[j].to]-=(double)1/Ind[i]; 73 } 74 for (int i=1; i<=n-1; ++i) f[n][i]=0; 75 f[n][n]=1;//钦定结果为0 76 Gauss(); 77 Ans+=ans[1]*(1<<k); 78 } 79 printf("%.3lf",Ans); 80 }