骰子游戏 (牛客)

35 篇文章 0 订阅
23 篇文章 0 订阅

骰子游戏  牛客链接

题目描述:

小易参加了一个骰子游戏,这个游戏需要同时投掷n个骰子,每个骰子都是一个印有数字1~6的均匀正方体。
小易同时投掷出这n个骰子,如果这n个骰子向上面的数字之和大于等于x,小易就会获得游戏奖励。
小易想让你帮他算算他获得奖励的概率有多大。

输入描述:

输入包括两个正整数n和x(1 ≤ n < 25, 1 ≤ x < 150),分别表示骰子的个数和可以获得奖励的最小数字和。

输出描述:

输出小易可以获得奖励的概率。
如果概率为1,输出1,如果概率为0,输出0,其他以最简分数(x/y)的形式输出。

解题思路:

可能出现的值的范围为:n~6*n

1、回溯法

回溯法枚举n个骰子(6面)的全排列,然后计算每一次排列所有值的和,并统计该和的出现的次数,除以6^n(全排列的全部可能性),即为概率。

2. dp

假设f(m,s)表示投第m个骰子时,点数之和s出现的次数,投第m个骰子时的点数之和只与投第m-1个骰子时有关。
递归方程:f(m,s)=f(m-1,s-1)+f(m-1,s-2)+f(m-1,s-3)+f(m-1,s-4)+f(m-1,s-5)+f(m-1,s-6),表示本轮点数和为s出现次数等于上一轮点数和为s-1,s-2,s-3,s-4,s-5,s-6出现的次数之和。
初始条件:第一轮的f(1),f(2),f(3),f(4),f(5),f(6)均等于1.
需要求的是:f(n , n)、 f(n, n+1)....f(n, 6*n)
下面的代码: 是用了空间压缩的dp,并且一定要注意 dp数组应该是long long,因为全部排列的6^n 很大,用int会溢出

 vector<vector<long long>> dp(2,vector<long long>(6*n,0));

代码:

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;


int main(){
    int n, x;
    cin>>n>>x;
    vector<long long> dp(6*n+1);
    for (int i= 1; i <= 6; i++)
        dp[i] = 1;
    
    for (int i = 2; i<=n; i++){
        for(int j = 6*i; j>= i; j--){
            dp[j] = 0;
            for (int k = 1; k <= 6 && k <= j-i+1; k++){
                // 上一轮的 点数范围在 【i-1,6*i(i-1)】
                // 所以如果 j-k 小于 i-1 则越界了
                dp[j] += dp[j-k];
            }
        }
    }
    
    long long ok_sum = 0;
    long long all_sum = pow(6, n);
    x = max(x, n);
    for (int i = x; i<= 6*n; i++){
        ok_sum += dp[i];
    }

    
    if (ok_sum == 0)
        cout << 0 << endl;
    else if (ok_sum == all_sum)
        cout << 1 << endl;
    else{
        while (all_sum % 2 == 0 && ok_sum % 2 == 0){
            all_sum /= 2;
            ok_sum /= 2;
        }
        while (all_sum % 3 == 0 && ok_sum % 3 == 0){
            all_sum /= 3;
            ok_sum /= 3;
        }
        cout << ok_sum <<'/' << all_sum << endl;

    }
        
    
    
    
    
    
}

另外再附上,求最大公约数的代码:

long gcd(long a, long b) {
    long t = a % b;
    while (t) {
        a = b; b = t; t = a % b;
    }
    return b;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值