第一題

【題目描述】

有一個點數爲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 }
AC代碼
相關文章
相關標籤/搜索