天天看点

3446. 骰子点数之和问题

单点时限: 2.0 sec

内存限制: 256 MB

/

double probability(int n, int k) { //TODO: your function definition

}

#include <stdio.h>

int main() {

int n, k;

scanf("%d%d", &n, &k);

printf("%.6f\n", probability(n, k));

return 0;

}

骰子的六面分别是 1,2,3,4,5,6。

样例

input

2 6

output

0.138889

提示

每题共有 10 组测试数据。

对于测试点 1,2,3,1≤n≤3,输出与答案误差不超过 10−3 认为正确。

对于测试点 4,5,6,7,1≤n≤10,输出与答案误差不超过 10−3 认为正确。

对于测试点 8,9,10,1≤n≤2 000,输出与答案误差不超过 10−6 认为正确。

对于所有测试点,1≤k≤109。

思路一:题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。

解题思路:

第一步,确定问题解的表达式。可将f(n, s) 表示n个骰子点数的和为s的排列情况总数。

第二步,确定状态转移方程。n个骰子点数和为s的种类数只与n-1个骰子的和有关。因为一个骰子有六个点数,那么第n个骰子可能出现1到6的点数。所以第n个骰子点数为1的话,f(n,s)=f(n-1,s-1),当第n个骰子点数为2的话,f(n,s)=f(n-1,s-2),…,依次类推。在n-1个骰子的基础上,再增加一个骰子出现点数和为s的结果只有这6种情况!那么有:

f(n,s)=f(n-1,s-1)+f(n-1,s-2)+f(n-1,s-3)+f(n-1,s-4)+f(n-1,s-5)+f(n-1,s-6) ,0< n<=6n

f(n,s)=0, s< n or s>6n

上面就是状态转移方程,已知初始阶段的解为:

当n=1时, f(1,1)=f(1,2)=f(1,3)=f(1,4)=f(1,5)=f(1,6)=1。

很显然思路一不行,数据太大了。

思路二:

用dp[i][j]表示第i次和位j的概率,初始时dp[1][1]=dp[1][2]=dp[1][3]=dp[1][4]=dp[1][5]=dp[1][6]=1/6。其实就是思路一的拓展。

//思路一递归代码:
int fun(int n, int count) {
    if (count < n || n< 1 || count > 6*n)
        return 0;
    if (n == 1)
        return 1;
    int ans = fun(n - 1, count - 1) + fun(n - 1, count - 2) + fun(n - 1, count - 3)
        + fun(n - 1, count - 4) + fun(n - 1, count - 5) + fun(n - 1, count - 6);
    return ans;
}`
`
//思路二:滚动数组+dp
#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n, k, x, y;
    cin>>n>>k;
    long double dp[7][12001];
    long double p=1.0/6.0;
    if(k>n*6 || k<n) {cout<<0; return 0;}
    for(int i=1; i<7; i++) dp[1][i]=p;
    for(int i=2; i<=n; i++)
    {
        x=i%7;//当前次
        y=(i-1)%7;//上一次
        for(int j=i; j<=6*i; j++)
        {
            dp[x][j]=0;
            if(j>6 && j>=i+5) {dp[x][j]+=dp[y][j-6]*p;}
            if(j>5 && j>=i+4) {dp[x][j]+=dp[y][j-5]*p;}
            if(j>4 && j>=i+3) {dp[x][j]+=dp[y][j-4]*p;}
            if(j>3 && j>=i+2) {dp[x][j]+=dp[y][j-3]*p;}
            if(j>2 && j>=i+1) {dp[x][j]+=dp[y][j-2]*p;}
            dp[x][j]+=dp[y][j-1]*p;
        }
    }
    printf("%.6llf\n",dp[n%7][k]);
    return 0;
}
           

继续阅读