BZOJ 3143 游走 | 数学期望 高斯消元

Posted 胡小兔的OI博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3143 游走 | 数学期望 高斯消元相关的知识,希望对你有一定的参考价值。

啊 我永远喜欢期望题

BZOJ 3143 游走

题意

有一个n个点m条边的无向联通图,每条边按1m编号,从1号点出发,每次随机选择与当前点相连的一条边,走到这条边的另一个端点,一旦走到n号节点就停下。每经过一条边,要付出这条边的编号这么多的代价。现将所有边用1m重新编号,使总代价的期望最小,求这个最小值。

题解

我们可以求出每条边的期望经过次数,然后贪心地让经过次数多的边编号小即可。

直接用边来列方程求经过次数似乎列不出来,我们借助点来列方程。

设x[u]为从某个点出发的次数的期望,v为与u相连的点,d[v]为点d的度,则:

\\[x[u] = \\sum \\frac{x[v]}{d[v]} \\]

特殊地,不能从点n出发,所以x[n] = 0;第一次从点1出发,\\(x[u] = 1 + \\sum \\frac{x[v]}{d[v]}\\)

解出所有x后,设一条边的两个端点是u和v,则经过每条边的次数的期望是:

\\[\\frac{x[u]}{d[u]} + \\frac{x[v]}{d[v]} \\]

代码如下:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define space putchar(\' \')
#define enter putchar(\'\\n\')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < \'0\' || c > \'9\')
	if(c == \'-\') op = 1;
    x = c - \'0\';
    while(c = getchar(), c >= \'0\' && c <= \'9\')
	x = x * 10 + c - \'0\';
    if(op) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar(\'-\'), x = -x;
    if(x >= 10) write(x / 10);
    putchar(\'0\' + x % 10);
}

const int N = 505, M = 250005;
int n, m, u[M], v[M], d[N];
double ans[M], x[N], f[N][N], res;
void build(){
    for(int i = 1; i <= n; i++)
	f[i][i] = -1;
    for(int e = 1; e <= m; e++){
	f[u[e]][v[e]] += 1.0 / d[v[e]];
	f[v[e]][u[e]] += 1.0 / d[u[e]];
    }
    for(int i = 1; i <= n; i++)
	f[n][i] = 0;
    f[n][n] = 1, f[n][n + 1] = 0;
    f[1][n + 1] = -1;
}
void Gauss(){
    for(int i = 1; i <= n; i++){
	int l = i;
	for(int j = i + 1; j <= n; j++)
	    if(fabs(f[j][i]) > fabs(f[l][i])) l = j;
	if(l != i)
	    for(int j = i; j <= n + 1; j++)
		swap(f[i][j], f[l][j]);
	for(int j = n + 1; j >= i; j--)
	    f[i][j] /= f[i][i];
	for(int j = i + 1; j <= n; j++)
	    for(int k = n + 1; k >= i; k--)
		f[j][k] -= f[j][i] * f[i][k];
    }
    for(int i = n; i; i--){
	x[i] = f[i][n + 1];
	for(int j = 1; j < i; j++)
	    f[j][n + 1] -= f[j][i] * x[i];
    }
}
int main(){
    read(n), read(m);
    for(int i = 1; i <= m; i++)
	read(u[i]), read(v[i]), d[u[i]]++, d[v[i]]++;
    build();
    Gauss();
    for(int i = 1; i <= m; i++)
	ans[i] = x[u[i]] / d[u[i]] + x[v[i]] / d[v[i]];
    sort(ans + 1, ans + m + 1);
    for(int i = 1; i <= m; i++)
	res += ans[i] * (m - i + 1);
    printf("%.3lf\\n", res);
    return 0;
}

以上是关于BZOJ 3143 游走 | 数学期望 高斯消元的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-3143游走 高斯消元 + 概率期望

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

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

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

bzoj3143 游走 概率 高斯消元

BZOJ 3143 游走(高斯消元)