「HNOI2013」游走

## [「HNOI2013」游走 ](https://loj.ac/problem/2383)

题目描述

一个无向连通图,顶点从 \(1\) 编号到 \(N\) ,边从 \(1\) 编号到 \(M\) 。小 \(Z\) 在该图上进行随机游走,初始时小 \(Z\)\(1\) 号顶点,每一步小 \(Z\) 以相等的概率随机选择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小 \(Z\) 到达 \(N\) 号顶点时游走结束,总分为所有获得的分数之和。

现在,请你对这 \(M\) 条边进行编号,使得小 \(Z\) 获得的总分的期望值最小。

\(N \leq 500\)


### 解题思路 :

考虑如果能算出每一条边期望的被经过次数,那么对此从大到小排序分配编号肯定最优.

观察发现,问题可以转化为求出每个点期望的被经过次数,然后分配到每一条边上

\(f[i]\) 表示点 \(i\) 期望的被经过次数,显然有 \(f[i] = \sum_{haveEdge(i,v)} \frac{f[v]}{deg_v}\) 其中 \(deg_v\) 表示点 \(v\) 的度数

考虑这是一张图,这样的转移并不满足子结构,不一定能找到合适的顺序进行 \(dp\) 处理

但是考虑到 \(N\) 比较小,每一个点的转移可以看做一个方程,所有点形成一个方程组,直接高斯消元求解即可

注意要从点 \(1\) 出发,点 \(N\) 结束,所以点 \(1\) 推出的方程要额外加上 \(1\) 的次数,点 \(N\) 不能作为转移到别人的点,不能加进方程组里


```cpp /*program by mangoyang*/ #include #define inf (0x7f7f7f7f) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) typedef long long ll; using namespace std; template inline void read(T &x){ int f = 0, ch = 0; x = 0; for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; if(f) x = -x; } #define par pair #define mp make_pair #define fi first #define se second const int N = 1005, M = 1000005; map s; double buf[M]; vector g[N]; int deg[N], a[M], n, m, col; typedef double Matrix[N][N]; Matrix A; inline bool cmp(int x, int y){ return buf[x] > buf[y]; } inline void Gauss(Matrix &A){ for(int i = 1; i <= n; i++){ int r = i; for(int j = i + 1; j <= n; j++) if(fabs(A[j][i]) > fabs(A[r][i])) r = j; for(int j = i; j <= n + 1; j++) swap(A[i][j], A[r][j]); for(int j = i + 1; j <= n; j++){ double f = A[j][i] / A[i][i]; for(int k = i; k <= n + 1; k++) A[j][k] -= A[i][k] * f; } } for(int i = n; i >= 1; i--){ for(int j = i + 1; j <= n; j++) A[i][n+1] -= A[j][n+1] * A[i][j]; A[i][n+1] /= A[i][i]; } } int main(){ read(n), read(m); for(int i = 1, x, y; i <= m; i++){ read(x), read(y); deg[x]++, g[x].push_back(y); deg[y]++, g[y].push_back(x); par now = mp(Min(x, y), Max(x, y)); if(!s[now]) s[now] = ++col; } for(int i = 1; i <= n; i++){ for(auto v : g[i]) if(v != n) A[i][v] = 1.0 / (double) deg[v]; A[i][i] = -1; A[i][n+1] = i == 1 ? -1 : 0; } Gauss(A); for(int i = 1; i < n; i++){ double val = A[i][n+1]; for(auto v : g[i]){ int c = s[mp(Min(i, v), Max(i, v))]; buf[c] += val / (double) deg[i]; } } for(int i = 1; i <= m; i++) a[i] = i; sort(a + 1, a + m + 1, cmp); double ans = 0; for(int i = 1; i <= m; i++) ans += (double) i * buf[a[i]]; printf("%.3lf", ans); return 0; } ```
posted @ 2018-07-25 16:15  Joyemang33  阅读(113)  评论(0编辑  收藏  举报