191:钉子和小球
总时间限制:
1000ms
内存限制:
65536kB
描述
有一个三角形木板,竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。
让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图2就是小球一条可能的路径。
我们知道小球落在第i个格子中的概率pi=,其中i为格子的编号,从左至右依次为0,1,...,n。
现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。
输入
第1行为整数n(2 <= n <= 50)和m(0 <= m <= n)。以下n行依次为木板上从上至下n行钉子的信息,每行中'*'表示钉子还在,'.'表示钉子被拔去,注意在这n行中空格符可能出现在任何位置。
输出
仅一行,是一个既约分数(0写成0/1),为小球落在编号为m的格子中的概pm。既约分数的定义:A/B是既约分数,当且仅当A、B为正整数且A和B没有大于1的公因子。
样例输入
5 2
*
* .
* * *
* . * *
* * * * *
样例输出
7/16
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 const int maxn=55; 5 int n,m; 6 long long f[maxn][maxn]; 7 char ch; 8 long long gcd(long long x,long long y) 9 { 10 if(x%y==0) return y; 11 return gcd(y,x%y); 12 }//最大公约数 13 14 int main() 15 { 16 scanf("%d%d",&n,&m);//n行 第m个 17 f[1][1]=(long long)1<<n;//便于求概率 18 for(int row=1;row<=n;row++) 19 { 20 for(int col=1;col<=row;col++) 21 { 22 do scanf("%c",&ch); 23 while(ch!='*'&&ch!='.'); 24 if(ch=='*') 25 { 26 f[row+1][col]=f[row+1][col]+f[row][col]/2; 27 f[row+1][col+1]=f[row+1][col+1]+f[row][col]/2; 28 //碰上钉子右向左向右两种可能 29 }else f[row+2][col+1]+=f[row][col]; 30 //没有碰上时直接落下,就加上了上面空缺的地方的概率 31 } 32 } 33 long long xi=gcd(f[n+1][m+1],(long long)1<<n);//最大公约数 34 cout<<f[n+1][m+1]/xi<<"/"<<((long long)1<<n)/xi<<endl;//以最简形式输出 35 return 0; 36 }