有一個點數爲n,邊數爲m的無向連通圖,點編號1~n,邊有權值。如今隨機選擇一條從點1出發到點n的路徑(按照每次的出邊等機率隨機的方式,第一次到達n後即結束),將路徑上全部邊的權值和進行異或做爲路徑的權值,求此圖路徑權值的指望。圖可能有重邊和自環。自環爲單項邊。html
輸入第一行包含兩個空格隔開的正整數n,m,以後m行每行三個整數,表示一條邊的起點終點和權值。ide
輸出一個實數,保留到三位小數表示指望。spa
2 2
1 1 1
1 2 0
0.333
走自環奇數次則爲1,偶數次則爲0.指望爲無窮等比級數之和1/4+1/16+1/64+……=1/3.code
對於20%的數據點,n=2。htm
對於40%的數據點,2 ≤ n ≤ 10。blog
對於第五、6個數據點,權值只爲0或1.get
對於100%的數據點,2 ≤ n ≤ 100,0 ≤ 權值 ≤ 32767,1 ≤ m ≤ 1000。it
先看這題,而後再看這題會不會有什麼感想?io
如何處理異或呢?說到位運算就想到拆位。拆了拆了。event
而後發現每一個點只能是0/1,而後稍加思索,左思右想,空氣力學分析可得:
每一個點分爲0和1兩個狀態,而後根據邊的值來在4個狀態之間連邊。
那麼每一條邊的貢獻就是 (機率(0->1) - 機率(1->0)) * 邊權。
一共搞15次就行了。
1 #include <cstdio> 2 #include <bitset> 3 #include <algorithm> 4 #include <cmath> 5 const int N = 205, M = 1010, lm = 15; 6 const double eps = 1e-12; 7 8 int n, l[M], r[M], c[M], out[N]; 9 double a[N][N], f[N]; 10 11 inline void clear() { 12 for(int i = 1; i <= (n << 1); i++) { 13 for(int j = 1; j <= (n << 1 | 1); j++) { 14 a[i][j] = 0.0; 15 } 16 f[i] = 0.0; 17 } 18 return; 19 } 20 21 inline void output() { 22 for(int i = 1; i <= (n << 1); i++) { 23 for(int j = 1; j <= (n << 1 | 1); j++) { 24 printf("%6.3lf ", a[i][j]); 25 } 26 puts(""); 27 } 28 puts(""); 29 return; 30 } 31 32 inline void Gauss() { 33 for(int i = 1; i < (n << 1); i++) { 34 for(int j = i; j <= (n << 1); j++) { 35 if(fabs(a[j][i]) > eps) { 36 std::swap(a[i], a[j]); 37 break; 38 } 39 } 40 for(int j = i + 1; j <= (n << 1); j++) { 41 if(fabs(a[j][i]) < eps) { 42 continue; 43 } 44 double p = a[j][i] / a[i][i]; 45 for(int k = i; k <= (n << 1 | 1); k++) { 46 a[j][k] -= a[i][k] * p; 47 } 48 } 49 } 50 51 for(int i = (n << 1); i > 1; i--) { 52 for(int j = i - 1; j >= 1; j--) { 53 if(fabs(a[j][i]) < eps) { 54 continue; 55 } 56 double p = a[j][i] / a[i][i]; 57 a[j][i] = 0.0; 58 a[j][n << 1 | 1] -= p * a[i][n << 1 | 1]; 59 } 60 } 61 62 for(int i = 1; i <= (n << 1); i++) { 63 f[i] = a[i][n << 1 | 1] / a[i][i]; 64 } 65 return; 66 } 67 68 int main() { 69 int m; 70 scanf("%d%d", &n, &m); 71 72 for(int i = 1; i <= m; i++) { 73 scanf("%d%d%d", &l[i], &r[i], &c[i]); 74 out[l[i]]++; 75 if(l[i] != r[i]) { 76 out[r[i]]++; 77 } 78 } 79 80 double ans = 0.0; 81 82 for(int i = 0; i < lm; i++) { 83 if(i) { 84 clear(); 85 } 86 for(int j = 1; j <= m; j++) { 87 int x = l[j], y = r[j], t = (c[j] >> i) & 1; 88 double ox = 1.0 / out[x], oy = 1.0 / out[y]; 89 if(x == y) { 90 if(x == n) { 91 continue; 92 } 93 if(t) { 94 a[x][x + n] += ox; 95 a[x + n][x] += ox; 96 } 97 else { 98 a[x][x] += ox; 99 a[x + n][x + n] += ox; 100 } 101 continue; 102 } 103 if(x < n) { 104 if(t) { 105 a[y][x + n] += ox; 106 a[y + n][x] += ox; 107 } 108 else { 109 a[y][x] += ox; 110 a[y + n][x + n] += ox; 111 } 112 } 113 if(y < n) { 114 if(t) { 115 a[x][y + n] += oy; 116 a[x + n][y] += oy; 117 } 118 else { 119 a[x][y] += oy; 120 a[x + n][y + n] += oy; 121 } 122 } 123 } 124 for(int j = 1; j <= (n << 1); j++) { 125 a[j][j] -= 1.0; 126 } 127 a[1][n << 1 | 1] = -1.0; 128 129 Gauss(); 130 131 int base = 1 << i; 132 for(int j = 1; j <= m; j++) { 133 if(((c[j] >> i) & 1) == 0) { 134 continue; 135 } 136 int x = l[j], y = r[j]; 137 double ox = 1.0 / out[x]; 138 double oy = 1.0 / out[y]; 139 140 if(x == y) { 141 if(x == n) { 142 continue; 143 } 144 ans += (f[x] - f[x + n]) * ox * base; 145 continue; 146 } 147 if(x < n) { 148 ans += (f[x] - f[x + n]) * ox * base; 149 } 150 if(y < n) { 151 ans += (f[y] - f[y + n]) * oy * base; 152 } 153 } 154 } 155 156 printf("%.3lf", ans); 157 158 return 0; 159 }