第一题

【题目描述】

有一个点数为n,边数为m的无向连通图,点编号1~n,边有权值。现在随机选择一条从点1出发到点n的路径(按照每次的出边等概率随机的方式,第一次到达n后即结束),将路径上所有边的权值和进行异或作为路径的权值,求此图路径权值的期望。图可能有重边和自环。自环为单项边。

【输入】

输入第一行包含两个空格隔开的正整数n,m,之后m行每行三个整数,表示一条边的起点终点和权值。

【输出】

输出一个实数,保留到三位小数表示期望。

【输入样例】

2 2
1 1 1
1 2 0

【输出样例】

0.333

【提示】

走自环奇数次则为1,偶数次则为0.期望为无穷等比级数之和1/4+1/16+1/64+……=1/3.

对于20%的数据点,n=2。

对于40%的数据点,2 ≤ n ≤ 10。

对于第5、6个数据点,权值只为0或1.

对于100%的数据点,2 ≤ n ≤ 100,0 ≤ 权值 ≤ 32767,1 ≤ m ≤ 1000。

先看这题,然后再看这题会不会有什么感想?

如何处理异或呢?说到位运算就想到拆位。拆了拆了。

然后发现每个点只能是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代码

 

posted @ 2018-08-04 15:30  garage  阅读(163)  评论(0编辑  收藏  举报