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

3 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游走高斯消元的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3143[Hnoi2013]游走 期望DP+高斯消元

BZOJ3143HNOI2013游走 高斯消元

BZOJ3143 - HNOI2013游走高斯消元

bzoj 3143 [Hnoi2013]游走 期望dp+高斯消元

BZOJ3143: [Hnoi2013]游走 期望+高斯消元

[BZOJ 3143][Hnoi2013]游走(高斯消元+期望)