数学期望在算法中的应用

ops/2024/11/28 17:56:40/

数学期望算法中的应用

数学期望是概率论和统计学中的一个核心概念,主要用于描述所有数据的平均值或者是中心趋势。在计算机算法竞赛中,期望算法属于一个中高等难度的算法,在程序设计中发挥着至关重要的作用。在近些年的 CSP/ USACO 等国际知名算法竞赛中,期望期望动态规划算法常常被作为考试题目。因此,本文将详细讲述数学期望算法中的应用。

为了降低本文的阅读门槛,本文会提供诸多例子来帮助读者来理解期望的定义和期望的实际应用。在文章的最后,我也会向大家提供相关的算法练习题。

随机变量的基本概念

在了解期望之前,务必要了解一下 随机变量 Random Variable 的定义。

随机变量是一个 函数,它将随机实验的每一个可能结果映射到一个数值。随机变量可以看作是随机现象的数学表达。

E.g. 1 投掷硬币

以投掷一枚硬币举例子:

  • 有两个实验结果:正面 ( H \mathtt{H} H)、反面 ( T \mathtt{T} T)。
  • 随机变量 X X X:定义为正面记作 1 1 1,反面记作 0 0 0
E.g. 2 投掷骰子

在投掷骰子时:

  • 有六个实验结果: 1 , 2 , 3 , 4 , 5 , 6 1, 2, 3, 4, 5, 6 1,2,3,4,5,6
  • 随机变量 Y Y Y:定义为投掷出的点数的值。

数学期望的基本概念

教科书上对于 期望 Expectation 的定义如下:

数学期望,简称期望,是对随机变量取值的加权平均,其权重为对应取值的概率。

一个更直观的说法是:期望值代表了大量重复实验中,随机变量取值的平均水平,是对随机现象的一种 集中趋势 的描述。

E.g. 3 考试评分

假设一门考试有五道选择题,得分规则如下:

  1. 选择正确答案获得 4 4 4 分。
  2. 选择错误答案扣除 1 1 1 分。
  3. 未作答不增加也不扣除分数。

如果考生随机选择答案,每道题的概率为:

  1. 做对这道题的概率为: 1 4 \dfrac{1}{4} 41
  2. 做错这道题的概率为: 3 4 \dfrac{3}{4} 43

那么这场考试每道题的期望得分为:
E ( X ) = 4 × 1 4 + ( − 1 ) × 3 4 = 1 − 0.75 = 0.25 E(X) = 4\times \dfrac{1}{4} + (-1) \times \dfrac{3}{4} = 1- 0.75 = 0.25 E(X)=4×41+(1)×43=10.75=0.25
这意味着,随机作答的长期平均得分是每道题 0.25 0.25 0.25 分。

E.g. 4 概率游戏 I \mathrm{I} I

有一个掷骰子的游戏,规则是如果投掷出点数 6 6 6 10 10 10 分,投掷出其余点数扣 2 2 2 分。那么:

  • 投掷出 6 6 6 的概率是: 1 6 \dfrac{1}{6} 61
  • 投掷出其他点数的概率是: 5 6 \dfrac{5}{6} 65

期望得分为:
E ( X ) = 10 × 1 6 + ( − 2 ) × 5 6 = 10 6 − 10 6 = 0 E(X) = 10\times\dfrac{1}{6} + (-2)\times \dfrac{5}{6} = \dfrac{10}{6} - \dfrac{10}{6} = 0 E(X)=10×61+(2)×65=610610=0
因此从长远来看(假如一直玩这个游戏的话),这个游戏是公平的,没有任何的得分优势。

通过这两个例子应该就能够很容易地理解期望在数学中的定义和作用了。

期望的线性叠加和独立性

期望是可以叠加的,假设有两个事件(两个事件可以是相互独立的,也可以是相互依赖的),两个事件的期望分别为 E ( A ) E(\Alpha) E(A) E ( B ) E(\Beta) E(B),那么这两个事件的整体期望 E ( A + B ) E(\Alpha + \Beta) E(A+B) 可以直接被拆解成 E ( A ) + E ( B ) E(\Alpha) + E(\Beta) E(A)+E(B)

这说明 期望的计算可以逐项分解并加权,无论这些随机变量是否独立。

E.g. 5 概率游戏 I I \mathrm{II} II

有一个概率游戏,分为两轮:

  1. 第一轮:玩家投掷一个六面骰子,得分为骰子的点数。
  2. 第二轮:玩家掷两个六面骰子,得分为两个点数之和。

目标:要求计算玩家的总期望得分。

对于这种题目,我们就可以利用期望的线性叠加来完成。以下是一些变量的定义:

  1. 第一轮得分:随机变量 X 1 X_1 X1,取值为 1 , 2 , 3 , 4 , 5 , 6 1, 2, 3, 4, 5, 6 1,2,3,4,5,6
  2. 第二轮得分:随机变量 X 2 X_2 X2,为两个骰子的点数之和,取值为 2 , 3 , ⋯ , 11 , 12 2, 3, \cdots, 11, 12 2,3,,11,12
  3. 总得分的随机变量 S = X 1 + X 2 S = X_1 + X_2 S=X1+X2

根据期望的线性叠加性质:
E ( S ) = E ( X 1 ) + E ( X 2 ) E(S) = E(X_1) + E(X_2) E(S)=E(X1)+E(X2)
我们可以分别计算两个随机变量的期望,并将结果相加就可以计算出整一个概率游戏的期望得分了。

经过计算(本文不再详细举例相同的期望得分计算过程,具体可以自己手动推导),两轮游戏的期望得分分别为:

  1. 第一轮: E ( X 1 ) = 21 6 = 3.5 E(X_1) = \dfrac{21}{6} = 3.5 E(X1)=621=3.5
  2. 第二轮: E ( X 2 ) = 252 36 = 7 E(X_2) = \dfrac{252}{36} = 7 E(X2)=36252=7

那么总期望得分就是:
E ( S ) = E ( X 1 ) + E ( X 2 ) = 3.5 + 7 = 10.5 E(S) = E(X_1) + E(X_2) = 3.5 + 7 = 10.5 E(S)=E(X1)+E(X2)=3.5+7=10.5
也就是说,如果玩家无限地玩这个游戏,平均下来每一轮的得分大约为 10.5 10.5 10.5

期望的基本算法

期望在计算机的应用也非常的广泛,这里提供几个实际的算法题目来帮助读者加深对期望的理解。

E.g. 6 随机交换序列

题目描述

给定一个长度为 n n n 的序列,每个元素为 a 1 , a 2 , ⋯ , a − 1 , a n a_1, a_2, \cdots, a_{-1}, a_{n} a1,a2,,a1,an。每一步操作为选择两个不同位置的 i i i j j j,满足 1 ≤ i , j ≤ n , i ≠ j 1 \le i, j\le n, i \neq j 1i,jn,i=j,并交换 a i a_i ai a j a_j aj 的值。假设进行无限次随机交换操作后,求每一个位置上的最终数字的期望值。

解题思路

在进行了无限次随机交换次数后,序列将趋于均匀的随机排列。由于所有的排列的概率都是相同的,那么每个位置上的元素的期望值应为序列的平均值。

数学证明

设序列的总和为 S = Σ i = 1 n a i S = \Sigma_{i=1}^{n}a_i S=Σi=1nai,平均值为 μ = S n \mu = \dfrac{S}{n} μ=nS。在进行无限次随机交换后,每个位置上的元素均可能是任意一个 a i a_i ai,因此期望值均为 μ \mu μ

C++ 代码实现

本题的 C++ 代码实现如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;int main(){int n; cin >> n;vector<long long> a(n);double sum = 0.0;for(auto &x: a){cin >> x;sum += x;}double average = sum / n;// 输出每个位置的期望for(int i=0;i<n;i++){printf("%.6lf ", average);}return 0;
}
E.g. 7 彩票中奖期望

题目描述

你正参加一个彩票游戏,每张彩票有两个号码,分别是红球和篮球。红球的号码范围从 1 1 1 R R R 中选择,篮球的号码从 1 1 1 B B B 中选择。每张彩票的中奖条件是红球和篮球都正确。已知你购买了 k k k 张不同的彩票,求中奖的期望次数。

解题思路

首先先求出每张彩票的中奖概率为 1 R × 1 B = 1 R B \dfrac{1}{R} \times \dfrac{1}{B} = \dfrac{1}{RB} R1×B1=RB1。购买 k k k 张独立的彩票,每张彩票的中奖次数都是独立的,因此总的中奖次数的期望就是 k × 1 R B k \times \dfrac{1}{RB} k×RB1

C++ 代码实现

本题的 C++ 代码实现如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;int main(){long long R, B, k;cin >> R >> B >> k;double E = (double)k / (R * B);printf("%.6lf\n", E);return 0;
}
E.g. 8 期望步数达到目标

题目描述

在一个二维平面网格上,从起点 ( 0 , 0 ) (0, 0) (0,0) 开始,目标是到达终点 ( n , m ) (n, m) (n,m)。每一步,你可以选择向右或者向上移动。向右移动的概率为 p p p,向上移动的概率为 1 − p 1 - p 1p。求从起点到达终点的期望步数。

解题思路

相比较前面几道题目,这道题的难度有所提升。这是一个典型的动态规划期望相结合的问题。我们设置 d p i , j dp_{i, j} dpi,j 表示从点 ( i , j ) (i, j) (i,j) 到达终点的期望步数。

状态转移方程:

  • 如果当前坐标是终点,即 i = n i = n i=n j = m j = m j=m 时,则 d p i , j = 0 dp_{i, j} = 0 dpi,j=0,表示期望 0 0 0 步就可以到达终点。
  • 如果在边界移动(即 i = n i = n i=n j = m j = m j=m 时),只能单向移动:
    • d p i , j = 1 + d p i , j + 1 dp_{i, j} = 1 + dp_{i, j+1} dpi,j=1+dpi,j+1(向右移动)
    • d p i , j = 1 + d p i + 1 , j dp_{i, j} = 1 + dp_{i+1, j} dpi,j=1+dpi+1,j(向上移动)
  • 其他情况:
    • d p i , j = 1 + p × d p i , j + 1 + ( 1 − p ) × d p i + 1 , j dp_{i, j} = 1 + p \times dp_{i, j+1} + (1 - p) \times dp_{i+1, j} dpi,j=1+p×dpi,j+1+(1p)×dpi+1,j

计算顺序:从终点开始,逆序填充 d p dp dp 表格。

C++ 代码实现

本题的 C++ 代码实现如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;typedef long long ll;int main(){int n, m; double p;int dp[505][505];cin >> n >> m >> p;for(int i=n; i>=0; i--){for(int j=m; j>=0; j--){if(i == n && j == m){dp[i][j] = 0.0;continue;}if(i == n) dp[i][j] = 1.0 + dp[i][j+1];else if(j == m) dp[i][j] = 1.0 + dp[i+1][j];else dp[i][j] = 1.0 + p * dp[i][j+1] +(1.0 - p) * dp[i+1][j];}}printf("%.6lf\n", dp[0][0]);return 0;
}
E.g. 9 P1365 WJMZBMR打osu! / Easy

解题思路

这也是一道经典的期望动态规划的例题,与前面的题目都相同,我们先定义 d p i dp_i dpi 表示以第 i i i 个字符结尾的期望得分,用变量 l e n \mathtt{len} len 来表示连续的 o 字符出现的个数(且需要包含 s t r i str_i stri 的回合)。根据字符串的三种字符分类进行讨论:

  1. 当当前字符为 x 的时候:

    说明本回合游戏失败,期望得分将不会增加,也不会减少(与 d p i − 1 dp_{i-1} dpi1 相同)。与此同时,需要将 l e n \mathtt{len} len 归零,表示截至目前不存在连续的 o

  2. 当当前的字符为 o 的时候:

    说明本回合游戏胜利,期望得分应该就是截止上一轮游戏的期望得分 d p i − 1 dp_{i-1} dpi1 加上这轮游戏的期望得分 ( l e n + 1 ) 2 − l e n 2 (\mathtt{len} + 1)^2 - \mathtt{len}^2 (len+1)2len2(撤销长度为 l e n \mathtt{len} len 的连击得分,增加长度为 l e n + 1 \mathtt{len} + 1 len+1期望得分。化简可得: d p i = d p i − 1 + 2 × l e n + 1 dp_i = dp_{i-1} + 2\times \mathtt{len} + 1 dpi=dpi1+2×len+1。同时在更新完 d p dp dp 数组后将 l e n \mathtt{len} len 设置为 l e n + 1 \mathtt{len} + 1 len+1

  3. 当当前字符为 ? 的时候:

    我们需要同时考虑胜利或者失败两种情况((成功的期望 + 失败的期望) / 2):
    d p i = d p i − 1 + ( ( l e n + 1 ) 2 − l e n 2 ) + 0 2 = d p i − 1 + l e n + 0.5 dp_i = dp_{i-1} + \dfrac{((\mathtt{len} + 1)^2 - \mathtt{len}^2) + 0}{2} = dp_{i-1} + \mathtt{len} + 0.5 dpi=dpi1+2((len+1)2len2)+0=dpi1+len+0.5
    与此同时需要把 l e n \mathtt{len} len 更新为 ( l e n + 1 ) + 0 2 = l e n + 1 2 \dfrac{(\mathtt{len} + 1) + 0}{2} = \dfrac{\mathtt{len} + 1}{2} 2(len+1)+0=2len+1

接下来直接遍历就好了。

C++ 代码实现

本题的 C++ 代码实现如下:

#include <iostream>
#include <algorithm>
using namespace std;constexpr int N = 3e5 + 5;
int n; char c;
long double len, dp[N];int main(){ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);cin >> n;for (int i=1; i<=n; i++){cin >> c;switch (c){case '?': dp[i] = dp[i-1] + len + 0.5;len = (len + 1) / 2; break;case 'o': dp[i] = dp[i-1] - len * len + (len + 1) * (len + 1); len++; break;case 'x': dp[i] = dp[i-1]; len = 0; break;}}printf("%.4Lf\n", dp[n]);return 0;
}

算法的时间复杂度为 O ( n ) O(n) O(n),空间复杂度也是 O ( n ) O(n) O(n),但考虑到每一个 d p i dp_i dpi 永远只依赖自己上一个状态( d p i − 1 dp_{i-1} dpi1),因此可以进一步把代码的空间复杂度降低到 O ( 1 ) O(1) O(1)

E.g. 10 P1850 [NOIP2016 提高组] 换教室

这道题是 NOIP 2016 年比赛的原题,可以看出期望动态规划确实是一项重点。

解题思路

相同地,我们在一开始也需要定义 d p dp dp 状态。定义 d p i , j , k dp_{i, j, k} dpi,j,k 表示走到了第 i i i 点,申请了 j j j 次换课,当前次 换 / 不换 ( 1 / 0 ) \mathtt{换/不换}(1/0) /不换(1/0)期望。代码用 m a p a , b map_{a, b} mapa,b 来表示地图中 a a a b b b 两点的最短路(由于数据范围和需要求解多源最短路径的需求,这里使用 Floyd 算法来计算最短路径)。

状态转移:

  • 未换课 ( d p i , j , 0 dp_{i, j, 0} dpi,j,0):

    • 情况 1:上一步也未换课:
      d p i , j , 0 = d p i − 1 , j , 0 + map [ c [ i − 1 ] ] [ c [ i ] ] dp_{i, j, 0} = dp_{i-1, j, 0} + \text{map}[c[i-1]][c[i]] dpi,j,0=dpi1,j,0+map[c[i1]][c[i]]

    • 情况 2:上一步换课:
      d p i , j , 0 = d p i − 1 , j , 1 + map [ c [ i − 1 ] ] [ c [ i ] ] ⋅ ( 1 − k [ i − 1 ] ) + map [ d [ i − 1 ] ] [ c [ i ] ] ⋅ k [ i − 1 ] dp_{i, j, 0} = dp_{i-1, j, 1} + \text{map}[c[i-1]][c[i]] \cdot (1 - k[i-1]) + \text{map}[d[i-1]][c[i]] \cdot k[i-1] dpi,j,0=dpi1,j,1+map[c[i1]][c[i]](1k[i1])+map[d[i1]][c[i]]k[i1]

  • 换课 ( d p i , j , 1 dp_{i, j, 1} dpi,j,1):

    • 情况 1:上一步未换课:
      d p i , j , 1 = d p i − 1 , j − 1 , 0 + map [ c [ i − 1 ] ] [ d [ i ] ] ⋅ k [ i ] + map [ c [ i − 1 ] ] [ c [ i ] ] ⋅ ( 1 − k [ i ] ) dp_{i, j, 1} = dp_{i-1, j-1, 0} + \text{map}[c[i-1]][d[i]] \cdot k[i] + \text{map}[c[i-1]][c[i]] \cdot (1 - k[i]) dpi,j,1=dpi1,j1,0+map[c[i1]][d[i]]k[i]+map[c[i1]][c[i]](1k[i])

    • 情况 2:上一步换课:
      d p i , j , 1 = d p i − 1 , j − 1 , 1 + map [ d [ i − 1 ] ] [ d [ i ] ] ⋅ k [ i − 1 ] ⋅ k [ i ] + map [ d [ i − 1 ] ] [ c [ i ] ] ⋅ k [ i − 1 ] ⋅ ( 1 − k [ i ] ) + map [ c [ i − 1 ] ] [ d [ i ] ] ⋅ ( 1 − k [ i − 1 ] ) ⋅ k [ i ] + map [ c [ i − 1 ] ] [ c [ i ] ] ⋅ ( 1 − k [ i − 1 ] ) ⋅ ( 1 − k [ i ] ) dp_{i, j, 1} = dp_{i-1, j-1, 1} + \\ \text{map}[d[i-1]][d[i]] \cdot k[i-1] \cdot k[i] + \\ \text{map}[d[i-1]][c[i]] \cdot k[i-1] \cdot (1 - k[i]) + \\ \text{map}[c[i-1]][d[i]] \cdot (1 - k[i-1]) \cdot k[i] + \\ \text{map}[c[i-1]][c[i]] \cdot (1 - k[i-1]) \cdot (1 - k[i]) dpi,j,1=dpi1,j1,1+map[d[i1]][d[i]]k[i1]k[i]+map[d[i1]][c[i]]k[i1](1k[i])+map[c[i1]][d[i]](1k[i1])k[i]+map[c[i1]][c[i]](1k[i1])(1k[i])

C++ 代码实现

本题的 C++ 代码实现如下:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;constexpr int N = 2005;
constexpr int V = 305, E = 90000;
int n, m, v, e;
int c[N], d[N];
double k[N];
long long map[V][V];
// dp[i][j][k] 表示走到第 i 个点,申请了 j 次,
// 当前次 申请/不申请 (k) 的期望
double dp[N][N][2];int main(){ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);cin >> n >> m >> v >> e;for (int i=1; i<=n; i++) cin >> c[i];for (int i=1; i<=n; i++) cin >> d[i];for (int i=1; i<=n; i++) cin >> k[i];for (int i=1; i<=v; i++){for (int j=1; j<=v; j++){map[i][j] = 0x7f7f7f7f;}map[i][i] = map[i][0] = map[0][i] = 0;}for (int i=1; i<=e; i++){int a, b, w;cin >> a >> b >> w;map[a][b] = map[b][a] = min(map[a][b], 1LL * w);}for (int k=1; k<=v; k++){for (int i=1; i<=v; i++){for (int j=1; j<=v; j++){map[i][j] = min(map[i][k] + map[k][j], map[i][j]);}}}for (int i=0; i<=n; i++){for (int j=0; j<=m; j++){dp[i][j][0] = dp[i][j][1] = 1e9;}}dp[1][0][0] = dp[1][1][1] = 0;for (int i=2; i<=n; i++){dp[i][0][0] = dp[i-1][0][0] + map[c[i-1]][c[i]];for (int j=1; j<=min(i, m); j++){int C1 = c[i-1], C2 = d[i-1], C3 = c[i], C4 = d[i];dp[i][j][0] = min(dp[i][j][0], min(dp[i-1][j][0] + map[C1][C3], dp[i-1][j][1] + map[C1][C3] * (1 - k[i-1]) + map[C2][C3] * k[i-1]));dp[i][j][1] = min(dp[i][j][1], min(dp[i-1][j-1][0] + map[C1][C3] * (1 - k[i]) + map[C1][C4] * k[i],dp[i-1][j-1][1] + map[C2][C4] * k[i] * k[i-1] + map[C2][C3] * k[i-1] * (1 - k[i]) +map[C1][C4] * (1 - k[i-1]) * k[i] + map[C1][C3] * (1 - k[i-1]) * (1 - k[i])));}}double ans = 1e9;for (int i=0; i<=m; i++){ans = min(ans, dp[n][i][0]);ans = min(ans, dp[n][i][1]);}printf("%.2lf", ans);return 0;
}
E.g. 11 P1654 OSU!

与【E.g. 9 [P1365 WJMZBMR打osu! / Easy]】类似,稍作修改即可。

解题思路

要求解 x 3 x^3 x3期望,那么肯定需要维护 x 2 x^2 x2 x x x期望才可以。

具体地:

  1. a [ i ] a[i] a[i] 表示以第 i i i 个位置为终点, x x x期望
  2. b [ i ] b[i] b[i] 表示以第 i i i 个位置为终点, x 2 x^2 x2期望
  3. d p [ i ] dp[i] dp[i] 表示以第 i i i 个位置为终点, x 3 x^3 x3期望

递推公式:

  • a [ i ] = ( a [ i − 1 ] + 1 ) ∗ p [ i ] a[i] = (a[i-1] + 1) * p[i] a[i]=(a[i1]+1)p[i]
    • a [ i − 1 ] a[i-1] a[i1] 是上一轮的 x x x期望,加上当前位置的贡献 1 ⋅ p [ i ] 1 \cdot p[i] 1p[i]
  • b [ i ] = ( b [ i − 1 ] + 2 ⋅ a [ i − 1 ] + 1 ) ⋅ p [ i ] b[i] = (b[i-1] + 2 \cdot a[i-1] + 1) \cdot p[i] b[i]=(b[i1]+2a[i1]+1)p[i]
    • 上一轮的 x 2 x^2 x2期望加上新的贡献,其中包含 2 ⋅ a [ i − 1 ] ⋅ 1 2 \cdot a[i-1] \cdot 1 2a[i1]1 1 2 1^2 12
  • d p [ i ] = d p [ i − 1 ] + ( 3 ⋅ ( a [ i − 1 ] + b [ i − 1 ] ) + 1 ) ⋅ p [ i ] dp[i] = dp[i-1] + (3 \cdot (a[i-1] + b[i-1]) + 1) \cdot p[i] dp[i]=dp[i1]+(3(a[i1]+b[i1])+1)p[i]
    • 最后将所有 x 3 x^3 x3期望累加到当前 d p dp dp 状态。

C++ 代码实现

本题的 C++ 代码实现如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;constexpr int N = 3e5 + 5;
int n;
long double p[N], dp[N], a[N], b[N];int main(){ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);cin >> n;for (int i=1; i<=n; i++) cin >> p[i];for (int i=1; i<=n; i++){a[i] = (a[i-1] + 1) * p[i];b[i] = (b[i-1] + 2 * a[i-1] + 1) * p[i];dp[i] = dp[i-1] + (3 * (a[i-1] + b[i-1]) + 1) * p[i];}printf("%.1Lf\n", dp[n]);return 0;
}

常见问题与误区

误区一:期望值与实际值混淆

期望值代表随机变量的平均水平,但这并不意味着随机变量每次实验都恰好等于期望值。期望式大量实验后的平均结果,而非单次实验的确定结果。

误区二:忽略条件期望

在复杂问题中,忽视条件期望可能导致错误的期望计算,尤其是在存在依赖关系或多阶段决策的问题中。例如,在【E.g. 8 期望步数达到目标】中,如果忽略了当前位置的条件(当前坐标),会导致状态转移方程的错误,从而会计算出错误的期望步数。

参考文献

  • GeeksforGeeks. “ML | Expectation-Maximization Algorithm.” GeeksforGeeks, https://www.geeksforgeeks.org/ml-expectation-maximization-algorithm/.
  • Bee, Chloe. “The EM Algorithm Explained.” Medium, https://medium.com/@chloebee/the-em-algorithm-explained-52182dbb19d9.
  • Williams, Richard. “The Expectation Maximization (EM) Algorithm.” University of Notre Dame, https://www3.nd.edu/~rwilliam/stats1/x12.pdf.

http://www.ppmy.cn/ops/137427.html

相关文章

Python爬虫爬取网页小说

分析 注意&#xff1a;不同小说url不同&#xff0c;不同小说需采用的正则也不同 1.安装requests包 pip install requests2.导入必要的库 re模块用于进行正则表达式相关的操作&#xff0c;比如使用正则表达式在获取到的网页文本内容中匹配提取特定格式的信息。 resquests模块用…

使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件

使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件 Python 是一门强大的编程语言&#xff0c;它不仅可以用于数据处理、自动化脚本&#xff0c;还可以用于创建图形用户界面 (GUI) 应用程序。在本教程中&#xff0c;我们将使用 Python 的标准库模块 tkinter 创建一…

daos源码编译

1. 前言 本文详细介绍如何在almalinux8.9上编译daos.2.0.0源码。系统环境如下&#xff1a; daos: 2.0.0 linux os: almalinux 8.9 linux kernel: 4.18.0-513.5.1.el8_9.x86_64之所以选择2.0.0版本&#xff0c;是因为daos从2.0.0开始是一个全新的架构设计&a…

Rust语言俄罗斯方块(漂亮的界面案例+详细的代码解说+完美运行)

tetris-demo A Tetris example written in Rust using Piston in under 500 lines of code 项目地址: https://gitcode.com/gh_mirrors/te/tetris-demo 项目介绍 "Tetris Example in Rust, v2" 是一个用Rust语言编写的俄罗斯方块游戏示例。这个项目不仅是一个简单…

【Qt】控件7

1.QTextEdit的简单使用 使用简单的QTextEdit,获取到的内容显示到标签上 使用textChanged信号 在槽函数中需要获取QTextEdit的内容&#xff0c;对应操作是&#xff1a; QString curorui->textEdit->toPlainText();然后显示到标签上&#xff0c;对应操作是&#xff1a; …

vue3 reactive响应式实现源码

Vue 3 的 reactive 是基于 JavaScript 的 Proxy 实现的&#xff0c;因此它通过代理机制来拦截对象的操作&#xff0c;从而实现响应式数据的追踪。下面是 Vue 3 的 reactive 源码简化版。 Vue 3 reactive 源码简化版 首先&#xff0c;我们需要了解 reactive 是如何工作的&…

蓝桥杯每日真题 - 第23天

题目&#xff1a;&#xff08;直线&#xff09; 题目描述&#xff08;12届 C&C B组C题&#xff09; 解题思路&#xff1a; 题目理解: 在平面直角坐标系中&#xff0c;从给定的点集中确定唯一的直线。 两点确定一条直线&#xff0c;判断两条直线是否相同&#xff0c;可通过…

蓝牙循环搜索并连接. Android辅助功能以及锁的灵活运用

现在需要实现个工具, android设备要不断自动的去搜索附近蓝牙打印机,然后进行配对,连接打印数据. 根据测试发现有两个技术难点 第一个是一些设备链接打印机后,会弹出进行配对的对话框,有些设备还会让你输入配对密码进行配对,如果用人工去点击,就不是自动去搜索配对,并打印了…