BZOJ3143 - HNOI2013游走高斯消元
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3143 - HNOI2013游走高斯消元相关的知识,希望对你有一定的参考价值。
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
2 3
1 2
1 3
Sample Output
HINT
显然每个点的期望为 ex[ i ] = sum( exist_edge ( j , i ) , ex [ j ] / deg [ j ] ) , 把左侧移到右边后得到方程.
那么每条边e(i , j) = ex[ i ] / deg[ i ] + ex[ j ] / deg[ j ]
然后运用到一个结论:有不降序数列A 与 B 且 A与B中元素数量相同均为m,有P为1~m的一个排列,则A[1] * B[m] + ... + A[m] * B[1] <= A[1] * B[p[1]] + ... + A[m] * B[p[m]] <= A[1] * B[1] + ... + A[m] * B[m]
要注意点n的特殊性,它原本期望为1,但每个点不能由它转移过去,
它的期望也与其它点无关,就让它为0以方便计算;
精度杀...
#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> using namespace std; const int V = 505; const int E = 250005; const double eps = 1e-8; struct edge{ int fro, nxt, to; }e[E << 1]; int n, m; int fir[V], deg[V], cnt = 0; double M[V][V], sol[V], ex[E]; inline void add(int x, int y) { e[++ cnt].to = y; e[cnt].fro = x; e[cnt].nxt = fir[x]; fir[x] = cnt; } inline int sgn(double x) { if (fabs(x) < eps) return 0; if (x > 0) return 1; return -1; } inline void Gauss() { for (int i = 1; i <= n; i ++) { for (int j = i; j <= n; j ++) if (sgn(M[j][i])) { swap(M[i], M[j]); break; } if (!sgn(M[i][i])) return; double tmp = 1.0 / M[i][i]; for (int j = i; j <= n + 1; j ++) M[i][j] *= tmp; for (int j = i + 1; j <= n; j ++) if (sgn(M[j][i])) { tmp = M[j][i]; for (int l = i; l <= n + 1; l ++) M[j][l] -= M[i][l] * tmp; } } for (int i = n; i >= 1; i --) { for (int j = i + 1; j <= n; j ++) M[i][n + 1] -= M[i][j] * sol[j]; sol[i] = M[i][n + 1]; } } inline bool cmp(double a, double b) { return a > b; } int main() { int x, y; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i ++) { scanf("%d%d", &x, &y); add(x, y); add(y, x); deg[x] ++; deg[y] ++; } for (int i = 1; i < n; i ++) { M[i][i] = - 1.0; for (int j = fir[i]; j; j = e[j].nxt) M[i][e[j].to] += 1.0 / deg[e[j].to]; } M[1][n + 1] = - 1.0; M[n][n] = 1.0; for (int i = 1; i <= n; i ++) for (int j = 1; j <= n + 1; j ++) M[i][j] *= 100; Gauss(); for (int i = 1; i <= m; i ++) { x = e[i * 2].fro; y = e[i * 2].to; ex[i] = sol[x] * 1.0 / deg[x] + sol[y] * 1.0 / deg[y]; } sort(ex + 1, ex + m + 1, cmp); double ans = 0; for (int i = 1; i <= m; i ++) ans += 1.0 * i * ex[i]; printf("%.3lf\n", ans); return 0; }
以上是关于BZOJ3143 - HNOI2013游走高斯消元的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ3143[Hnoi2013]游走 期望DP+高斯消元
bzoj 3143 [Hnoi2013]游走 期望dp+高斯消元