UVA 1637 NEERC 2005 (全概率公式)

25 篇文章 0 订阅

UVA 1637 NEERC 2005 (全概率公式)

首先熟悉概率公式的定义:
P(A)=P(A|B1)*P(B1)+P(A|B2)*P(B2)+P(A|B3)*P(B3)+…+P(A|Bn)*P(Bn),其中B1∪B2∪…∪Bn构成事件空间的全集。

这道题的意思是,有36张牌,分成9叠,每叠4张,每次可以任从两叠的顶端取两张相同的牌,直到取完即为成功,如果当前情况有有种选择,每种选择的概率的相等的,求成功的概率。

我们可以用一个九元组<a1,a2,…,a9>表示当前的状态,其中ai表示第i叠还有几张牌,取值为0~4,所以我们可以用一个5进制整数取表示一个状态,在dfs时进行解码和编码即可。可以用数组dp[x]记录当前状态下的概率,这样就不用重复计算相同状态。递归边界时dp[0]=1.0。

不要想的太复杂,一开始我想着解码和编码进行的整数运算太多会不会导致很慢,以至于我换成用二进制取表示状态且用位运算进行解码和编码。这样一来不仅仅多出了许多无用的状态数,大大浪费了空间,而且每次用memset初始化一个大数组会带来一定耗时,速度反而变得很慢。

并不是一个难题

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int max_n=2e6;
int card[10][5];
double dp_[max_n];
bool vis[max_n];
double dp(int cur)
{
	if(vis[cur])return dp_[cur];
	double ans=0.0;
	vis[cur]=1;
	int cnt=0;
	int a[9];
	int t=cur;
	for(int i=0;i<9;i++)
	{
		a[i]=t%5;
		t/=5;
	}
	for(int i=0;i<9;i++)
	for(int j=i+1;j<9;j++)
	if(a[i]&&a[j]&&card[i][a[i]]==card[j][a[j]])
	{
		a[i]--;a[j]--;
		cnt++;
		int ne=0;
		for(int k=8;k>=0;k--)
		ne=ne*5+a[k];
		ans+=dp(ne);
		a[i]++;a[j]++;
	}
	if(cnt==0) return dp_[cur]=0.0;
	return dp_[cur]=ans/cnt;
}
int main(void)
{
	string s;
//	freopen("out.txt","w",stdout);
	int start=0;
	for(int i=0;i<9;i++)
		start=start*5+4;
	while(cin>>s)
	{
		memset(vis,0,sizeof(vis));
		dp_[0]=1.0;vis[0]=1;
		card[0][1]=s[0]-'0';
		for(int i=0;i<9;i++)
		for(int j=1;j<=4;j++)
		if(i==0&&j==1)continue;
		else{
			cin>>s;
			card[i][j]=s[0]-'0';
		}
		printf("%.6f\n",dp(start));
	}
//	fclose(stdout);
}
//AS 9S 6C KS
//JC QH AC KH
//7S QD JD KD
//QS TS JS 9H
//6D TD AD 8S
//QC TH KC 8D
//8C 9D TC 7C
//9C 7H JH 7D
//8H 6S AH 6H
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值