转载http://martinblack954.blog.163.com/blog/static/186105210201154102623873/
题意:在一块木板上,钉上钉子,排布成等边三角形。一个球从顶部开始,自由下落。每碰到一个钉子以后,等概率地向两边继续滚。现从该等边三角形的钉子中,拔去其中某些钉子。求这个球从顶部开始下落,滚到底部某个格子的概率。
思路:DP模拟。逐步递推,分别计算每一层,滚到每一个口的概率。最后一层每个口的概率,就是对应底部每个格子的概率。每一个口的概率,若遇到一个钉子,则除以2后就是下一层对应两个口的概率;若没遇到钉子,则直接等于再下层的对应入口,即直接落下。一开始的初值,就是2^层数,即全部都是钉子时,第一个格子对应的概率。
PS:层数有50,所以初始概率需要long long。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int const maxn = 51 + 51 * 50 / 2;
int n, m;
long long dp[55][55];
bool triangle[maxn];
long long gcd(long long a, long long b)
{
if(b)
return gcd(b, a % b);
return a;
}
int main()
{
scanf("%d %d", &n, &m);
char s[5];
int index = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= i; j++)
{
scanf("%s", s);
if(s[0] == '*')
triangle[index++] = true;
else
triangle[index++] = false;
}
}
dp[1][1] = 1;
for(int i = 1; i <= n; i++)
dp[1][1] <<= 1;
for(int i = 1; i <= n; i++)
{
int id = i * (i - 1) / 2;
for(int j = 1; j <= i; j++)
{
if(triangle[id + j])
{
dp[i+1][j] += dp[i][j] >> 1;
dp[i+1][j+1] += dp[i][j] >> 1;
}
else
{
dp[i+2][j+1] += dp[i][j];
}
}
}
long long ans1 = dp[n+1][m+1];
long long ans2 = 0;
for(int i = 1; i <= n + 1; i++)
ans2 += dp[n+1][i];
long long k = gcd(ans1,ans2);
if(ans1 == 0)
{
ans2 = 1;
k = 1;
}
printf("%lld/%lld\n", ans1 / k, ans2 / k);
}