首页 > 代码库 > BZOJ3143 - HNOI2013游走【高斯消元】
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
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。
显然每个点的期望为 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游走【高斯消元】
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。