定义存储结构
结构体:卡牌抽取状态,层数(抽取次数),概率积
定义一个队列,模拟树的层次遍历过程
输入
读入卡牌总数n和硬币k换卡牌数
读入卡牌获得概率
利用队列模拟n叉树的层次遍历
每一个出队的结点
- 判断是否完成卡牌抽取
- 若完成,计算概率积,并累计求和
- 若未完成,继续抽牌,生成子节点,计算概率积,并把子节点入队列
队列为空(遍历结束),输出结果
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
double p[16];//卡牌数n小于等于16,对应的概率数也小于等于16
int n,k;
struct node{
int state;//卡牌抽取状态[本质上是一个向量,某位为1,表示抽取到该位的牌]
int level;//层数(抽取次数)
double p;//概率积
};
int main(){
scanf("%d%d",&n,&k);//读入卡牌总数n和硬币k换卡牌数
for(int i=0;i<n;i++) scanf("%lf",p+i);//获得第i种卡牌的概率为p[i-1]
double ans = 0;//记录期望抽卡次数
node nodecur,nodechild;
queue<node> q;//定义一个队列,模拟树的层次遍历过程
//初试化根节点
nodecur.state = 0;
nodecur.level = 0;
nodecur.p = 1;
//开始n叉树的层次遍历
q.push(nodecur);
while(!q.empty()){
nodecur = q.front();
q.pop();
int cnt = 0;//记录抽取到的不同种类的牌数
for(int i=0;i<n;i++)
if((nodecur.state>>i)&1) cnt++;
//nodecur.level-cnt为硬币的个数
if(cnt+(nodecur.level-cnt)/k>=n){
ans = ans += nodecur.p * nodecur.level; //累加概率积*层数
continue;//此时,不需要生成子节点,直接跳过,原因在于已经符合条件,不需要继续抽牌
}
for(int i=0;i<n;i++){//生成子节点
nodechild.p = nodecur.p*p[i];//计算子节点的概率积
nodechild.state = nodecur.state|(1<<(n-i-1));
nodechild.level = nodecur.level + 1;
q.push(nodechild);//将子节点入队
}
}
printf("%.10lf\n",ans);//题目样例2保留到了小数点后的第10位
return 0;
}