[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 }
AC代码

 

posted @ 2018-08-03 16:26  huyufeifei  阅读(156)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜