BZOJ 3143: [Hnoi2013]游走
3143: [Hnoi2013]游走
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2429 Solved: 1049
[Submit][Status][Discuss]
Description
一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
Input
第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。
Output
仅包含一个实数,表示最小的期望值,保留3位小数。
Sample Input
3 3
2 3
1 2
1 3
2 3
1 2
1 3
Sample Output
3.333
HINT
边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。
Source
先求出每个点的期望经过次数,则每条边的经过次数为x点出发,走这条边的期望+y点出发,走这条边的概率。
1 #include <bits/stdc++.h> 2 3 inline char nextChar(void) 4 { 5 static const int siz = 1024; 6 7 static char buf[siz]; 8 static char *hd = buf + siz; 9 static char *tl = buf + siz; 10 11 if (hd == tl) 12 fread(hd = buf, 1, siz, stdin); 13 14 return *hd++; 15 } 16 17 inline int nextInt(void) 18 { 19 register int ret = 0; 20 register int neg = false; 21 register int bit = nextChar(); 22 23 for (; bit < 48; bit = nextChar()) 24 if (bit == '-')neg ^= true; 25 26 for (; bit > 47; bit = nextChar()) 27 ret = ret * 10 + bit - 48; 28 29 return neg ? -ret : ret; 30 } 31 32 int n, m; 33 34 struct edge 35 { 36 int x, y; 37 double k; 38 }e[500005]; 39 40 double f[505][505]; 41 42 int g[505][505], c[505]; 43 44 inline bool cmp(const edge &a, const edge &b) 45 { 46 return a.k > b.k; 47 } 48 49 signed main(void) 50 { 51 n = nextInt(); 52 m = nextInt(); 53 54 for (int i = 1; i <= m; ++i) 55 { 56 ++c[e[i].x = nextInt()]; 57 ++c[e[i].y = nextInt()]; 58 59 ++g[e[i].x][e[i].y]; 60 ++g[e[i].y][e[i].x]; 61 } 62 63 for (int i = 1; i < n; ++i) 64 for (int j = 1; j < n; ++j) 65 { 66 if (i == j) 67 f[i][j] = -1.0; 68 else 69 f[i][j] = 1.0 * g[i][j] / c[j]; 70 } 71 72 f[1][n] = -1.0; 73 74 { 75 for (int i = 1; i < n; ++i) 76 { 77 int r = i; 78 79 for (int j = i + 1; j < n; ++j) 80 if (fabs(f[j][i]) > fabs(f[r][i])) 81 r = j; 82 83 for (int j = 1; j <= n; ++j) 84 std::swap(f[i][j], f[r][j]); 85 86 for (int j = i + 1; j < n; ++j) 87 { 88 long double t = f[j][i] / f[i][i]; 89 90 for (int k = i; k <= n; ++k) 91 f[j][k] -= t * f[i][k]; 92 } 93 } 94 95 for (int i = n - 1; i >= 0; --i) 96 { 97 for (int j = i + 1; j < n; ++j) 98 f[i][n] -= f[j][n] * f[i][j]; 99 100 f[i][n] /= f[i][i]; 101 } 102 } 103 104 for (int i = 1; i <= m; ++i) 105 e[i].k = f[e[i].x][n] / c[e[i].x] + f[e[i].y][n] / c[e[i].y]; 106 107 std::sort(e + 1, e + m + 1, cmp); 108 109 double ans = 0.0; 110 111 for (int i = 1; i <= m; ++i) 112 ans += e[i].k * i; 113 114 printf("%.3lf\n", ans); 115 }
@Author: YouSiki