经典概率题等概率取数/蓄水池问题等

题目:给一副扑克牌和一个随机数函数,设计一个洗牌算法。

解析:
最直观的思路是什么?很简单,每次从牌堆中随机地拿一张出来。那么, 第一次拿有52种可能,拿完后剩下51张;第二次拿有51种可能,第三次拿有50种可能, …,一直这样随机地拿下去直到拿完最后1张,我们就从52!种可能中取出了一种排列, 这个排列对应的概率是1/(52!),正好是题目所要求的。

接下来的问题是,如何写代码去实现上面的算法?假设扑克牌是一个52维的数组cards, 我们要做的就是从这个数组中随机取一个元素,然后在剩下的元素里再随机取一个元素… 这里涉及到一个问题,就是每次取完元素后,我们就不会让这个元素参与下一次的选取。 这个要怎么做呢。

我们先假设一个5维数组:1,2,3,4,5。如果第1次随机取到的数是4, 那么我们希望参与第2次随机选取的只有1,2,3,5。既然4已经不用, 我们可以把它和1交换,第2次就只需要从后面4位(2,3,1,5)中随机选取即可。同理, 第2次随机选取的元素和数组中第2个元素交换,然后再从后面3个元素中随机选取元素, 依次类推。
代码:

#include <iostream>
#include <cstdlib>
using namespace std;

void Swap(int &a, int &b){// 有可能swap同一变量,不能用异或版本
    int t = a;
    a = b;
    b = t;
}
void RandomShuffle(int a[], int n){
    for(int i=0; i<n; ++i){
        int j = rand() % (n-i) + i;// 产生i到n-1间的随机数
        Swap(a[i], a[j]);
    }
}
int main(){
    srand((unsigned)time(0));
    int n = 9;
    int a[] = {
        1, 2, 3, 4, 5, 6, 7, 8, 9
    };
    RandomShuffle(a, n);
    for(int i=0; i<n; ++i)
        cout<<a[i]<<endl;
    return 0;
}

讲义讲解版本:

for i in 1...n

randomly select a card j from [1, i]

swap card i with card j

证明:

我们使?用数学归纳法进?行证明算法1的正确性:

每张牌出现在各个位置的概率相等(1/N)

当N = 1时,显然成?立

当N=2,每张牌出现在两个位置的概率都是1/2

假设当N=k时候成?立,我们现在证明N = k +1的时候也成?立,即每张牌出现出现在各个位置的概率均为1/(k + 1)

我们分三部分来看:第k+1张牌到所有位置,前k张牌到第k+1个位置,前k张牌到前k个位置

第k+1张牌到所有位置
显然,第k + 1张牌到所有位置的概率均为1/(k +1),算法就是这么写的:)

前k张牌到第k+1个位置

跟上?面同理,前k张牌被交换到第k + 1个位置的概率为1/(k +1)

前k张牌到前k个位置(最复杂):
我们知道N = k的时候成?立,所以不考虑第k+1张牌,前k张牌在前k个位置的概率是1/k

但现在,因为第k+1张牌的出现,我们还要保证前k张牌中的某?一张不被交换?走,这个概率是:(1 - 1/(k + 1))

所以根据?贝叶斯公式,最终的概率为:
1/k * (1 - 1/(k + 1)) = 1/(k + 1)

时间: 2024-07-30 12:34:31

经典概率题等概率取数/蓄水池问题等的相关文章

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数

线性规划与网络流24题●09方格取数问题&amp;13星际转移问题

●(做codevs1908时,发现测试数据也涵盖了1907,想要一并做了,但因为"技术"不佳,搞了一上午) ●09方格取数问题(codevs1907  方格取数3) 想了半天,也没成功建好图: 无奈下参考题解,说是本题要求二分图点权最大独立集,然后可以由结论:"最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流"转化到求最大流(我真的很懵逼,但又感觉很有道理): 下面附上solution:(自己领悟吧) (不懂

【网络流24题】方格取数问题

Description 在一个有m * n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. Input 第1 行有2 个正整数m和n,分别表示棋盘的行数和列数. 接下来的m行,每行有n个正整数,表示棋盘方格中的数. Output 将取数的最大总和输出 Sample Input 3 3 1 2 3 3 2 3 2 3 1 Sample Output

「网络流 24 题」方格取数

大意: 给定$n*m$棋盘, 每个格子有权值, 不能选择相邻格子, 求能选出的最大权值. 二分图带权最大独立集, 转化为最小割问题. S与$X$连边权为权值的边, $X$与$Y$之间连$INF$, $Y$与$T$连边权为权值的边. 则最大权值为总权值-最小割. 残量网络中与$S$相连的或与$T$相连的表示选择, 否则表示不选. #include <iostream> #include <sstream> #include <algorithm> #include <

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白

线性规划与网络流9 方格取数

算法实现题 8-9 方格取数问题(习题 8-20)?问题描述:在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件 input.txt 提供输入数据.文件第 1 行有 2 个正整数 m和 n,分别表示棋盘的行数和列数.接下来的 m行,每行有 n 个正整数,表示棋盘方格中的数.?结果输出:程序运行结束时,

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

概率题(一)

转载http://noalgo.info/414.html 概率论是计算机科学非常重要的基础学科之一,概率题也是在程序员求职过程中经常遇到的问题.以下总结若干经典的概率题,作为练习. 1. 在半径为1的圆中随机选取一点. 方法1:在x轴[-1,1],y轴[-1,1]的正方形随机选取一点,如果此点在圆内,则即为所求的点.如果不在圆内,则重新随机直到选到了为止. 方法2:从[0, 2*pi)随机选取一个角度,再在这个方向的半径上随机选取一个点.但半径上的点不能均匀选取,选取的概率要和离圆心的距离成正

概率题

题目1 (2014腾讯笔试题) 36辆车,6个跑道,最少轮数决出前3名. 分析 分6组,每组跑一次,进行排序. 然后每组第一快的人再跑一遍,确定最快的3组. 最后最快的第一组取3个人,第二快的人取2个人(因为最快的人一定在最快的第一组),第三快的人取1个人.共6个人.再跑一遍. 所以总共是6+1+1=8轮. 以下转自:http://www.acmerblog.com/interviews-about-probability-5359.html 题目2 假设你参加了一个游戏节目,现在要从三个密封的