题目大意:
每条路径上有一个距离值,从1走到N可以得到一个所有经过路径的异或和,求这个异或和的数学期望
这道题直接去求数学期望的DP会导致很难列出多元方程组
我们可以考虑每一个二进制位从1走到N的平均概率值
因为整个图是联通的那么所有点都默认会处于多元方程组中
Pi = p[i] * sigma( v&d[i][j]?(1-Pj):Pj)
v是当前二进制位代表的数值
这里需要注意的是自环的加边情况,自环只加一次边,不能向平时那样加无向边一样
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 using namespace std; 8 const int N = 205; 9 const int M = 10005; 10 #define eps 1e-8 11 int first[N] , k , degree[N] , n , m; 12 double p[N] , a[N][N]; 13 14 void debug() 15 { 16 for(int i=0 ; i<n ; i++){ 17 for(int j=0 ; j<=n ; j++) 18 cout<<a[i][j]<<" "; 19 cout<<endl; 20 } 21 } 22 23 struct Edge{ 24 int y , next , d; 25 Edge(int y=0 , int next=0 , int d=0):y(y),next(next),d(d){} 26 }e[M<<1]; 27 28 void add_edge(int x,int y,int d) 29 { 30 e[k] = Edge(y , first[x] , d); 31 first[x] = k++; 32 } 33 34 int get_width(int x) 35 { 36 int ret =0 ; 37 while(x) 38 { 39 x>>=1; 40 ret++; 41 } 42 return ret; 43 } 44 45 void build(int v) 46 { 47 memset(a , 0 , sizeof(a)); 48 for(int i=0 ; i<n ; i++){ 49 a[i][i] = 1; 50 if(i==n-1) continue; 51 for(int j=first[i] ; ~j ; j=e[j].next){ 52 int u = e[j].y; 53 if(v&e[j].d){ 54 a[i][u] += p[i]; 55 a[i][n] += p[i]; 56 }else{ 57 a[i][u] -= p[i]; 58 } 59 } 60 } 61 // debug(); 62 } 63 64 int gauss(int n) 65 { 66 int i,j,k; 67 for(i=0 , j=0 ; i<n&&j<n ; j++){ 68 for(k=i ; k<n ; k++) 69 if(fabs(a[k][j])>eps) break; 70 if(k<n){ 71 if(i!=k) 72 for(int r=j ; r<=n ; r++) swap(a[i][r],a[k][r]); 73 double tt = 1.0/a[i][j]; 74 for(int r=j ; r<=n ; r++) a[i][r] *= tt; 75 for(int r=0 ; r<n ; r++){ 76 if(r == i) continue; 77 for(int t=n ; t>=j ; t--) 78 a[r][t] -= a[i][t]*a[r][j]; 79 } 80 i++; 81 } 82 } 83 for(int r=i ; r<n ; r++) 84 if(fabs(a[r][n])>eps) return 0; 85 return 1; 86 } 87 88 int main() 89 { 90 #ifndef ONLINE_JUDGE 91 freopen("a.in" , "r" , stdin); 92 #endif // ONLINE_JUDGE 93 while(~scanf("%d%d" , &n , &m)) 94 { 95 memset(first , -1 , sizeof(first)); 96 memset(degree , 0 , sizeof(degree)); 97 k = 0; 98 int maxn = 0; 99 for(int i=0 ; i<m ; i++){ 100 int x,y,d; 101 scanf("%d%d%d" , &x , &y , &d); 102 add_edge(x-1,y-1,d); 103 if(x!=y){ 104 add_edge(y-1 , x-1 , d); 105 degree[x-1]++ , degree[y-1]++; 106 } 107 else degree[x-1]++; 108 maxn = max(maxn , d); 109 } 110 for(int i=0 ; i<n ; i++) p[i] = 1.0/(degree[i]*1.0);//得到从当前点每条边出发的概率 111 int len = get_width(maxn); 112 double ret= 0; 113 for(int i=0 ; i<len ; i++){ 114 int v = 1<<i; 115 build(v); 116 gauss(n); 117 ret += v*a[0][n]; 118 } 119 printf("%.3f\n" , ret); 120 } 121 return 0; 122 }
时间: 2024-10-04 14:29:37