POJ 1189 釘子和小球【基礎DP】

釘子和小球
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 8073   Accepted: 2516

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

Source


原題鏈接:http://poj.org/problem?id=1189

題目是中文就不多囉嗦了,但是有一點,如果某個點沒有釘子,那麼小球會落到下面第二層的位置。

理解以後就和POJ1136 The Triangle差不多了。

由於概率每次都要處於2,並且分數加法有點麻煩,所以,開始時一個數的值設爲2^n,

這樣便可簡化運算.

運算方法有兩種,

一.dp[i][j]+=(dp[i-1][j-1]+dp[i-1][j])/2;

二.dp[i+1][j]+=dp[i][j]/2,dp[i+1][j+1]+=dp[i][j]/2;

相對來說第二種方法更簡單一點.

樣例過程:

32
16 0
8 8 0
4 0 20 0
2 2 10 10 0
1 2 14 10 5 0

AC代碼:

/**
  * 行有餘力,則來刷題!
  * 博客鏈接:http://blog.csdn.net/hurmishine
  *
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn=50+5;
char a[maxn][maxn];
LL dp[maxn][maxn];
int n,m;
LL GCD(LL x,LL y)
{
    if(y==0)
        return x;
    return GCD(y,x%y);
}
int main()
{
    //freopen("C:\\Documents and Settings\\Administrator\\桌面\\data.txt","r",stdin);
    while(cin>>n>>m)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=i;j++)
                cin>>a[i][j];
        }
        memset(dp,0,sizeof(dp));
        LL maxx=(LL)1<<n;
        dp[0][0]=maxx;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=i;j++)
            {
                if(a[i][j]=='*')
                {
                    dp[i+1][j]+=dp[i][j]/2;
                    dp[i+1][j+1]+=dp[i][j]/2;
                }
                else
                {
                    dp[i+2][j+1]+=dp[i][j];
                    //dp[i][j]=0;
                }
            }
        }
        /**
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=i;j++)
                cout<<dp[i][j]<<" ";
            cout<<endl;
        }
        */
        //cout<<dp[n][m]<<endl;
        LL gcd=GCD(maxx,dp[n][m]);
        cout<<dp[n][m]/gcd<<"/"<<maxx/gcd<<endl;
    }
    return 0;
}



發佈了374 篇原創文章 · 獲贊 211 · 訪問量 70萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章