poj 1189 钉子和小球 一道有趣的题

来源:互联网 发布:剑三捏脸杨幂数据 编辑:程序博客网 时间:2024/05/01 02:08

一道有趣的题,不算难。


题目:

Description

有一个三角形木板,竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。
让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图2就是小球一条可能的路径。
我们知道小球落在第i个格子中的概率pi=pi=,其中i为格子的编号,从左至右依次为0,1,...,n。
现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。

Input

第1行为整数n(2 <= n <= 50)和m(0 <= m <= n)。以下n行依次为木板上从上至下n行钉子的信息,每行中'*'表示钉子还在,'.'表示钉子被拔去,注意在这n行中空格符可能出现在任何位置。

Output

仅一行,是一个既约分数(0写成0/1),为小球落在编号为m的格子中的概pm。既约分数的定义:A/B是既约分数,当且仅当A、B为正整数且A和B没有大于1的公因子。

Sample Input

5 2*   * .  * * * * . * ** * * * *

Sample Output

7/16

解法:明显的dp问题,但本人水平较弱,一直想着直接用分数计算,但精度不够。后经高人指点。假设有2^n个球掉下来,看最后落在格挡内有几个球就行了。

代码:

//By Sean Chen#include <iostream>#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>using namespace std;long long Map[55][55];int n,m;char s[55][110];int vis[55][55];long long power(int a,int b){    long long ans=1;    for (int i=1;i<=b;i++)        ans*=a;    return ans;}int main(){scanf("%d%d\n",&n,&m);for(int i=1;i<=n;i++)gets(s[i]);for(int i=1;i<=n;i++)for(int j=0,cnt=0;s[i][j]!='\0';j++)if(s[i][j]=='*' || s[i][j]=='.'){cnt++;if(s[i][j]=='.')vis[i][cnt]=1;      //处理输入的空格,用1表示. 用0表示*}Map[1][1]=power(2,n);      //2^n个球for(int i=1;i<=n;i++)for(int j=1; j<=i;j++){if(vis[i][j])Map[i+2][j+1]+=Map[i][j];        //没有钉子,直接落到下一层else{Map[i+1][j]+=Map[i][j]/2;        //有钉子,左右各分到一半的小球Map[i+1][j+1]+=Map[i][j]/2;}}if(Map[n+1][m+1]==0)           //没有小球落到格挡内printf("0/1\n");else{while(!(Map[n+1][m+1]&1))        {            Map[1][1]/=2;            Map[n+1][m+1]/=2;        }printf("%lld/%lld",Map[n+1][m+1],Map[1][1]);}return 0;}


0 0
原创粉丝点击