[题解] [笔记]期望&洛谷P3232

[题解] [笔记]期望&洛谷P3232

期望

概念

期望在信息学中指的一般是达到结果的期望,最简单的计算方法就是每个情况的概率乘以这个情况的结果的值

例题理解以及公式

问题1

持续地抛一枚硬币,直到连续两次硬币正面朝上,求期望要抛的次数

解答:设\(f_0\)为没有抛出过正面的期望次数,\(f_1\)为已经抛出一次正面还要再抛一个正面的期望次数,则可以得到

\[\begin{cases} f_0=0.5*(f_0+1)+0.5*(f1+1)\\ f_1=0.5*1+0.5*(f_0+1) \end{cases} \]

问题2

你面前有\(n\)扇门,每道门有一个战力要求\(c_i\)和时间\(t_i\)同时你有一个战斗力\(v\)。每一轮你都会随机挑选一扇门进行挑战:若\(v>c_i\)则会花费\(t_i\)的时间离开;否则战力提升\(c_i\)。求期望多少轮后能离开?\(n ≤ 100, v, c_i ≤ 10^4\)

解答:设\(f_i\)代表战力为\(i\)时期望的逃离时间,则可以知道:

\[\begin{cases} f_i+=\frac{1}{n}*f_{i+c_i}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i\leq c_i\\ f_i+=\frac{1}{n}*t_i\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i > c_i \end{cases} \]

问题3

买彩票。一张彩票\(2\)元,每卖出\(1000000\)张就开奖,中奖号码是\(342356\),每张彩票也是一个\(6\)位数的数字,奖励规则如下:

  • 最后一位相等奖励\(4\)元,中奖概率\(0.1\%\)

  • 后两位相等奖励\(20\)元,中奖概率\(0.01\%\)

  • 后三位相等奖励\(200\)元,中奖概率\(0.001\%\)

  • 后四位相等奖励\(2000\)元,中奖概率\(0.0001\%\)

  • 后五位相等奖励\(20000\)元,中奖概率\(0.00001\%\)

求彩票公司每卖出一张彩票的期望收益。

解答:通过上面两道比较简单的例题立即期望的概念,我们知道算期望就是把每种情况的权值与它对应的概率相乘。那么来看这道题。先计算公司的期望支出:\(0.1*4+0.01*20+0.001*2000+0.00001*20000=1.2\),也就意味着每卖出一张彩票公司的期望支出为\(1.2\)元,而彩票的单价是\(2\)元,所以公司每卖出一张彩票的期望收益就是\(0.8\)元。

公式

期望用\(E\)表示,概率用\(P\)表示,则有:\(E(x)=X_1*P(X_1)+X_2*P(X_2)+...+X_n*P(X_n)\)

题解

有了对期望的大致了解就可以来看洛谷的这道题了。

思路分析

根据贪心的原则,为了使答案尽可能的小,那么期望经过次数多的边的编号就要尽可能的小。那么问题就变成了求每条边的期望经过次数,那么再想一条边被经过肯定是由它的两个端点来的,那么就可以表示一下:\(g_e\)表示经过边\(e\)的期望次数,\(f\)表示点的期望经过次数,\(d\)表示点的入度,就\(g_e=\frac{f_u}{d_u}+\frac{f_v}{d_v}\),因为每次到达一个点\(u\)的时候都有\(\frac{1}{d_u}\)的概率经过边\(e\)。那么问题又转化成求经过点的期望次数:\(f_u=\sum_{v\in E_u}\frac{f_v}{d_v} \ \ {(E_u)表示的是和u相连的点集}\),但要注意\(1\)号节点不一样,\(f_1=1+\sum_{v\in E_u}\frac{f_v}{d_v}\),因为一开始就走过了,而\(n\)号节点是目标节点,走到了就不能再到别的点了所以\(f_n=0\)

接着就是求解了,我们可以把上面\(f\)的式子看作\(n-1\)个方程,用高斯消元求解就行。但这里既然是用高斯消元求解就要表示成格式统一的方程式,方法如下:

\[对于方程组中的某一个式子f_u=\sum_{v\in E_u}\frac{f_v}{d_v}\\ 把\sum展开成:f_u=a_1*f_1+a_2*f_2+...+a_n*f_n,a表示的就是系数,对于没有与u相连的点的系数就是0,n号点的系数也是0\\ 然后把等号左边变成0,就可以得到一个形式化的方程式:\\ a_1*f_1+a_2*f_2+...+a_n*f_n-f_u=0\\ 因此方程组中就是n个这样的方程了,就可以高斯消元了 \]

代码

#include <bits/stdc++.h>
using namespace std;
struct node{
    int to,nxt;
}e[125010 * 2];
int fir[510],tot,d[510];
int u[125010],v[125010];
void add(int x,int y){
    e[++tot].to = y;
    e[tot].nxt = fir[x];
    d[x]++;
    fir[x] = tot;
}
int n,m;
double eps = 1e-9;
double f[510][510],g[125010];
void gauss(){
    for(int i = 1;i <= n;i++){
        int now = i;
        for(int j = i + 1;j <= n;j++){
            if(fabs(f[j][i]) > fabs(f[now][i]))
                swap(now,j);
        }
        if(now != i)
            for(int j = 1;j <= n + 1;j++)
                swap(f[i][j],f[now][j]);
        if(fabs(f[i][i]) < eps)continue;
        for(int j = 1;j <= n;j++){
            if(j != i){
                double tmp = f[j][i] / f[i][i];
                for(int k = i + 1;k <= n + 1;k++){
                    f[j][k] -= f[i][k] * tmp;
                }
            }
        }
    }
    for(int i = 1;i <= n;i++){
        f[i][n + 1] /= f[i][i];
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i++){
        scanf("%d%d",&u[i],&v[i]); 
        add(u[i],v[i]);add(v[i],u[i]);
    }
    n--;//n号点不能转移
    f[1][n + 1] = -1.0;//模拟移项的过程
    for(int i = 1;i <= n;i++){
        f[i][i] = -1;
        for(int j = fir[i];j;j = e[j].nxt){
            if(e[j].to != n + 1)
                f[i][e[j].to] = 1.0 / d[e[j].to];
        }
    }
    gauss();
    for(int i = 1;i <= m;i++){
        g[i] = f[u[i]][n + 1] / d[u[i]] + f[v[i]][n + 1] / d[v[i]];
    }
    sort(g + 1,g + m + 1);
    double ans = 0.0;
    for(int i = 1;i <= m;i++){
        ans += g[i] * (m - i + 1);
    }
    printf("%.3lf\n",ans);
    return 0;
}
posted @ 2020-11-17 21:23  czyczy  阅读(202)  评论(0编辑  收藏  举报