其他分享
首页 > 其他分享> > 紫书学习 10.数学概念与方法--离散概率基础

紫书学习 10.数学概念与方法--离散概率基础

作者:互联网

古典概型及其应用

古典概型满足有限性和等可能性,常见的模型是抛硬币。

不求同年同月同日生

有n个人,求至少有两个人生日相同的概率。

每个人的生日有365种可能,因此样本的容量是\(365^n\)。

可以想到暴力的统计方法,恰好两人生日相同、恰好3人....恰好n人生日相同,相加即可,这样比较麻烦。

可以用间接法,先计算任意两个人生日都不相同的概率,再用1减去即可。

\[P=1-\frac{A_{365}^{n}}{365^n} \]

注意这里的n如果超过365,根据抽屉原理,就必然存在两个人生日相同了。

条件概率及其应用

条件概率公式如下:

\[P(A|B)=\frac{P(AB)}{P(B)} \]

其中,\(P(A|B)\)表示事件A在事件B的条件下发生的概率,\(P(AB)\)表示A,B同时发生的概率,\(P(B)\)表示B发生的概率。

应用:Probability|Given - UVA 11181 - Virtual Judge (vjudge.net)

大意:有n个人走进一家商店,每个人会买东西的概率是\(p_i\),最后有r个人买了东西,求出第i个人买了东西的概率。

分析:假设第i个人在有r个人买了东西的条件下买了东西的概率是\(P(A|B)\),r个人买了东西的概率是\(P(B)\),第i个人买了东西且r个人买了东西的概率是\(P(AB)\),则可得

\[P(A|B)=\frac{P(AB)}{P(B)} \]

\(P(B)\)​的计算方法:可以暴力求组合型枚举,枚举出是哪r个人买了东西,记录在q[i]中,得出表达式:

\[\prod p_i*(1-p_j) \]

其中下标i表示买了东西的,j对应没买的东西的。

\(P(AB)\)的计算方法:假设要计算的是第i个人买了东西且r个人买了东西的概率,可以先定下p[i]=1,再组合型枚举剩下的r-1个人,套类似\(P(B)\)的公式即可。

综合在一起,可以通过一次组合型枚举,枚举所有r个人买东西的方案,顺便就可以计算\(P(AB)\)。

CODE

const int N=25;
int n,r;
int q[N];
double p[N];
double f[N],tot;//f表示每个人对应的P(AB),tot表示P(B)

void dfs(int k,int pos){
	if(k>r){
		double res=1;
		for(int i=1;i<=n;i++){
			if(!q[i])res*=(1-p[i]);
			else res*=p[i];
		}

		tot+=res;
		for(int i=1;i<=n;i++)if(q[i])f[i]+=res;
		return;
	}
	
	for(int i=pos;i<=n;i++){
		q[i]=1;
		dfs(k+1,i+1);
		q[i]=0;
	}
}

int main(){
	int T=1;
	while(scanf("%d%d",&n,&r) && n){
		for(int i=1;i<=n;i++)scanf("%lf",&p[i]);
		
		memset(f,0,sizeof(f));
		tot=0;
		dfs(1,1);
		
		printf("Case %d:\n",T++);
		for(int i=1;i<=n;i++)printf("%.6lf\n",f[i]/tot);
	}
}

全概率公式及其应用

可以通过对样本空间的划分,得出概率的一个递推关系式,有点类似dp中对状态集合的划分。这里对样本空间的划分必须保证不重不漏。

以下为全概率公式:

\[P(A)=\sum P(A\mid B_i)*P(B_i) \]

紫书上的例子:假设考试考第\(k\)名的概率是\(P(B_k)\),考第\(k\)名被妈妈表扬的概率是\(P(A\mid B_k)\),因此被妈妈表扬的概率\(P(A)\)就可以用上述全概率公式求得。

应用:Double Patience - UVA 1637 - Virtual Judge (vjudge.net)

简单大意:有36张牌分成9堆,每堆4张牌,每次可以拿走牌堆顶部两张点数相同的牌,如果有多种拿法则等概率随机拿。如果最后拿完所有牌则游戏成功。给出牌堆,求成功的概率。

分析:可以用五进制数对牌堆每行有几张牌的状态进行压缩,例如初始状态(五进制数下):444444444,最多会有\(5^9=1953125\)种状态,假设在当前状态下获胜的概率是\(f(state)\),再根据每次拿牌的策略对样本空间进行划分,假设当前有tot种拿牌的方案,拿牌之后获胜的概率是\(f(t)\),根据全概率公式有:

\[f(state)=\sum f(t)*\frac{1}{tot} \]

(这不就是就是dp、记搜吗)

写一个记忆化搜索即可。

CODE:

const int N=1953125;
double f[N];
int st[N];
char s[10][5][3];
int pow5[11];
int cnt[11];

double dp(int state){
	if(state==0)return 1;//成功
	if(st[state])return f[state];//记搜
	int tot=0;

	for(int i=1;i<=9;i++){
		if(!cnt[i])continue;
		for(int j=i+1;j<=9;j++){
			if(!cnt[j])continue;
			if(s[i][cnt[i]][0]==s[j][cnt[j]][0]){
				int t=state;
				t=t-pow5[i-1]-pow5[j-1];
				cnt[i]--; cnt[j]--;
				f[state]+=dp(t);//全概率公式
				cnt[i]++; cnt[j]++;
				tot++;
			}
		}
	}

	st[state]=1;
	if(!tot)return 0;//不能再操作说明失败了
	else return f[state]/=tot;//否则计算概率
}

int main(){
	pow5[0]=1;
	for(int i=1;i<=9;i++){
		pow5[i]=pow5[i-1]*5;//用来做"位"运算操作
		cnt[i]=4;//表示每行有多少张牌
	}
	while(scanf("%s",s[1][1])!=EOF){//多组测试数据
		memset(st,0,sizeof(st));
		memset(f,0,sizeof(f));
		for(int j=2;j<=4;j++)scanf("%s",s[1][j]);
		for(int i=2;i<=9;i++){
			for(int j=1;j<=4;j++){
				scanf("%s",s[i][j]);
			}
		}

		printf("%.6lf\n",dp(N-1));//从满牌开始递归
	}
	return 0;
}

标签:10,概率,紫书,个人,--,东西,int,state,AB
来源: https://www.cnblogs.com/tshaaa/p/16499870.html