bzoj 3143 游走
阅读量:
searchstar
2019-11-08 10:08:13
Categories:
Tags:
Description:一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选
择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z
到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
2≤N≤500
要用高斯消元做。
定义f[i]为期望的到点i的次数,du[i]为点i的度数。那么有
与 相 邻
注意点n只进不出,所以它对其他点的到达次数没有贡献。
点1一开始就有一次到达。
我们现在有了n个n元一次方程。由于这个方程不规则,所以我们只能用数值解法来解这个方程。这里采用高斯消元法。
把f解出来后,就把走每条边的期望次数g[e]求出来。
然后从大到小排个序,从1到m标号即可。
代码:
#include <cstdio> #include <vector> #include <cmath> #include <cassert> #include <algorithm> #include <functional> using namespace std;#define MAXN 511 #define MAXM 250011 typedef pair<int , int > pii;const double eps = 1e-8 ;struct GRAPH { vector<vector<int > > s; void ClearEdges () { for (auto & i : s) { i.resize (0 ); } } void Init (int n) { ClearEdges (); s.resize (n + 1 ); } void AddUndi (int u, int v) { s[u].push_back (v); s[v].push_back (u); } }; struct MATRIX { vector<vector<double > > s; MATRIX () {} MATRIX (size_t a, size_t b) { resize (a, b); } inline size_t row () const { return s.size (); } inline size_t col () const { return s.at (0 ).size (); } void resize (size_t a, size_t b) { s.resize (a); for (size_t i = 0 ; i < a; ++i) s[i].resize (b); } void clear () { for (auto & i : s) for (auto & j : i) j = 0 ; } void swap_row (size_t i, size_t j, size_t k = 0 ) { for (; k < col (); ++k) swap (s[i][k], s[j][k]); } void sub_row (size_t i, size_t j, double d, size_t k = 0 ) { for (; k < col (); ++k) s[i][k] -= d * s[j][k]; } void ToUpper (MATRIX& b) { for (size_t i = 0 ; i < row (); ++i) { double maxv = fabs (s[i][i]); size_t mr = i; for (size_t j = i + 1 ; j < row (); ++j) { if (maxv < fabs (s[j][i])) { maxv = fabs (s[j][i]); mr = j; } } swap_row (i, mr, i); b.swap_row (i, mr); if (maxv < eps) continue ; for (size_t j = i + 1 ; j < row (); ++j) { double d = s[j][i] / s[i][i]; sub_row (j, i, d, i); b.sub_row (j, i, d); } } } }; MATRIX solve_destory (MATRIX& a, MATRIX& b) { a.ToUpper (b); for (int i = a.row () - 1 ; i; --i) { assert (fabs (a.s[i][i]) > eps); b.s[i][0 ] /= a.s[i][i]; for (int j = 0 ; j < i; ++j) { b.s[j][0 ] -= b.s[i][0 ] * a.s[j][i]; } } return b; } int main () { GRAPH g; static pii es[MAXM]; static double gs[MAXN]; int n, m; scanf ("%d%d" , &n, &m); g.Init (n); for (int i = 0 ; i < m; ++i) { scanf ("%d%d" , &es[i].first, &es[i].second); --es[i].first; --es[i].second; } for (int i = 0 ; i < m; ++i) { g.AddUndi (es[i].first, es[i].second); } MATRIX b (n, 1 ) ; b.clear (); b.s[0 ][0 ] = 1 ; MATRIX a (n, n) ; for (int i = 0 ; i < n; ++i) { a.s[i][i] = 1 ; for (int v : g.s[i]) { if (v != n-1 ) a.s[i][v] = -1.0 / g.s[v].size (); } } b = solve_destory (a, b); b.s[n-1 ][0 ] = 0 ; for (int i = 0 ; i < m; ++i) { gs[i] = b.s[es[i].first][0 ] / g.s[es[i].first].size () + b.s[es[i].second][0 ] / g.s[es[i].second].size (); } sort (gs, gs + m, greater <double >()); double ans = 0 ; for (int i = 0 ; i < m; ++i) { ans += gs[i] * (i + 1 ); } printf ("%.3f\n" , ans); return 0 ; }