码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-12-07 13:26:46      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:图片   def   题意   utc   code   最小值   std   tchar   namespace   

啊 我永远喜欢期望题 技术分享图片

BZOJ 3143 游走

题意

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

题解

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

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

设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 游走 | 数学期望 高斯消元

标签:图片   def   题意   utc   code   最小值   std   tchar   namespace   

原文地址:http://www.cnblogs.com/RabbitHu/p/BZOJ3143.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!