例10-12 *uva1637(概率dp)

时间:2023-03-09 21:49:58
例10-12  *uva1637(概率dp)

题意: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;
}