题意:36张扑克,平分成9摞,两张数字一样的可以拿走,每次随机拿两张,问能拿光的概率。
思路:
直接用搜索,表示出每摞剩余的牌数,然后利用全概率公式即可(P(A) = p(A|b1)*p(b1)+.....+p(A|bn)*p(bn))
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
typedef long long ll;
using namespace std;
int p[10];
int num[9][5];
double dp[5][5][5][5][5][5][5][5][5]; //不同状态时的概率
int vis[5][5][5][5][5][5][5][5][5]; //是否已经搜过
char t1[4],t2[4],t3[4],t4[4];double dfs(int x1,int x2,int x3,int x4,int x5,int x6,int x7,int x8,int x9)
{if(vis[x1][x2][x3][x4][x5][x6][x7][x8][x9])return dp[x1][x2][x3][x4][x5][x6][x7][x8][x9];vis[x1][x2][x3][x4][x5][x6][x7][x8][x9] = 1;int top[10] = {x1,x2,x3,x4,x5,x6,x7,x8,x9};int flag = 0;for(int i = 0; i < 9; i++) //判断是否已经取完{if(top[i]){flag = 1;break;}}if(!flag )return dp[x1][x2][x3][x4][x5][x6][x7][x8][x9] = 1.0;int pnum = 0;double sum = 0.0; //当前情况往下取成功的概率for(int i = 0; i < 9; i ++){for(int j = i+1; j < 9 && top[i] != 0; j++){if(num[i][top[i]] == num[j][top[j]]){top[i]--;top[j]--;pnum++; //当前情况下有多少种取法sum += dfs(top[0],top[1],top[2],top[3],top[4],top[5],top[6],top[7],top[8]); top[i]++;top[j]++;}}}if(sum > 0)dp[x1][x2][x3][x4][x5][x6][x7][x8][x9] =(sum/(1.0*pnum));return dp[x1][x2][x3][x4][x5][x6][x7][x8][x9];
}int main()
{while(scanf("%s%s%s%s",t1,t2,t3,t4) != EOF){num[0][1] = t1[0];num[0][2] = t2[0];num[0][3] = t3[0];num[0][4] = t4[0];for(int i = 1; i< 9; i++){scanf("%s%s%s%s",t1,t2,t3,t4);num[i][1] = t1[0];num[i][2] = t2[0];num[i][3] = t3[0];num[i][4] = t4[0];}memset(vis,0,sizeof(vis));memset(dp,0,sizeof(dp));dfs(4,4,4,4,4,4,4,4,4);printf("%.6lf\n",dp[4][4][4][4][4][4][4][4][4]);}return 0;
}