[HNOI2013]游走
大意:给定简单无向图,从1号点出发,等概率走路,到n号点停止。
求每条边经过的次数期望。
解:
边的期望可以由点的概率很容易推出来。
点的概率是互相关联的,比如1号一开始概率为1,但是可能出去之后就回来结果概率比1还大了,然后又会影响到别的点....
有一种高斯消元的感觉,再一看数据范围:刚好!那么就是你了!
每个点的概率应该是从所有边过来的概率之和。
注意:常数项全0是解不了的。但是我们的一号点有个常数项为1
为什么有个负号呢?
因为把a[1][1]*f[1]移过去之后刚好是f[1] - 1,这就没问题了。
其余的贡献加起来再加原来就有的1就是f[1]
n号点不能为其他任一点的概率做贡献。
然后我们就可以列方程,解方程,然后搞出答案了。
精度开到1e12,否则可能WA
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 const int N = 510; 5 const double eps = 1e-12; 6 7 struct Edge { 8 int v, nex; 9 }edge[N * N * 2]; int top = 1; 10 11 int e[N], out[N], n, m, t; 12 double a[N][N], f[N], b[N * N]; 13 14 inline void add(int x, int y) { 15 top++; 16 edge[top].v = y; 17 edge[top].nex = e[x]; 18 e[x] = top; 19 out[x]++; 20 return; 21 } 22 23 inline void Gauss() { 24 for(int i = 1; i < n; i++) { 25 for(int j = i; j <= n; j++) { 26 if(fabs(a[j][i]) > eps) { 27 std::swap(a[j], a[i]); 28 break; 29 } 30 } 31 for(int j = i + 1; j <= n; j++) { 32 if(fabs(a[j][i]) < eps) { 33 continue; 34 } 35 double p = a[j][i] / a[i][i]; 36 for(int k = i; k <= n + 1; k++) { 37 a[j][k] -= a[i][k] * p; 38 } 39 } 40 } 41 42 for(int i = n; i > 1; i--) { 43 for(int j = i - 1; j >= 1; j--) { 44 if(fabs(a[j][i]) < eps) { 45 continue; 46 } 47 double p = a[j][i] / a[i][i]; 48 for(int k = i; k <= n + 1; k++) { 49 a[j][k] -= a[i][k] * p; 50 } 51 } 52 } 53 54 for(int i = 1; i <= n; i++) { 55 f[i] = a[i][n + 1] / a[i][i]; 56 } 57 58 return; 59 } 60 61 int main() { 62 scanf("%d%d", &n, &m); 63 for(int i = 1, x, y; i <= m; i++) { 64 scanf("%d%d", &x, &y); 65 add(x, y); 66 add(y, x); 67 } 68 out[n] = 0; 69 70 for(int x = 1; x < n; x++) { 71 for(int i = e[x]; i; i = edge[i].nex) { 72 int y = edge[i].v; 73 a[y][x] = 1.0 / out[x]; 74 } 75 a[x][x] = -1.0; 76 } 77 a[1][n + 1] = -1.0; 78 a[n][n] = -1.0; 79 80 Gauss(); 81 82 for(int i = 2; i <= top; i += 2) { 83 ++t; 84 if(edge[i].v < n) { 85 b[t] = f[edge[i].v] / out[edge[i].v]; 86 } 87 if(edge[i ^ 1].v < n) { 88 b[t] += f[edge[i ^ 1].v] / out[edge[i ^ 1].v]; 89 } 90 } 91 92 std::sort(b + 1, b + t + 1); 93 94 double ans = 0; 95 for(int i = t; i >= 1; i--) { 96 ans += b[i] * (t + 1 - i); 97 } 98 99 printf("%.3lf", ans); 100 101 return 0; 102 }