2337. [HNOI2011]XOR和路径【高斯消元】

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 }

猜你喜欢

转载自www.cnblogs.com/refun/p/8966255.html