bluecode-摇骰子的胜利概率

15 阅读2分钟

问题描述

小U和小S正在玩一个有趣的骰子游戏。每个骰子都有固定数量的面数k,每一面的点数分别是1到k。小U拥有n个骰子,每个骰子i的面数是 a_i,摇到每一面的概率均为 1/a_i。小S则有m个骰子,每个骰子j的面数是 b_j,摇到每一面的概率均为 1/b_j

两人分别同时摇各自的骰子,并将摇出的点数相加,得分较高的一方获胜,得分相同则为平局。游戏只进行一次,没有重赛。现在小U想知道他获胜的概率是多少。你能帮他计算吗?(答案保留三位小数)

输入:

  • n:小U的骰子数量
  • m:小S的骰子数量
  • arrayN:小U的每个骰子面数
  • arrayM:小S的每个骰子面数

约束条件:

  • nmk为整数,数据范围 1 ≤ nmk ≤ 25

测试样例

样例1:

输入:n = 1, m = 3, arrayN = [8], arrayM = [2, 3, 4]
输出:0.255

样例2:

输入:n = 2, m = 2, arrayN = [3, 4], arrayM = [3, 3]
输出:0.5

样例3:

输入:n = 3, m = 1, arrayN = [2, 2, 2], arrayM = [4]
输出:0.844

#include <climits>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>

using namespace std;

// 计算单个玩家的点数总和概率分布
map<int, double>
calculate_probability_distribution(const vector<int> &dice_faces) {
  map<int, double> dp;
  dp[0] = 1.0; // 初始状态,总和为0的概率为1

  // 动态规划计算得分概率分布
  for (int faces : dice_faces) {
    map<int, double> new_dp;
    for (const auto &[current_sum, count] : dp) {
      for (int outcome = 1; outcome <= faces; outcome++) {
        new_dp[current_sum + outcome] += count;
      }
    }
    dp = new_dp;
  }

  // 归一化每个得分的概率
  double total_outcomes = 0.0;
  for (const auto &[key, value] : dp) {
    total_outcomes += value;
  }
  for (auto &[key, value] : dp) {
    value /= total_outcomes;
  }

  return dp;
}

double solution(int n, int m, vector<int> arrayN, vector<int> arrayM) {
  // 小U和小S的得分概率分布
  map<int, double> u_distribution = calculate_probability_distribution(arrayN);
  map<int, double> s_distribution = calculate_probability_distribution(arrayM);

  double u_win_probability = 0.0;

  // 计算小U的胜率
  for (const auto &[u_sum, u_prob] : u_distribution) {
    double s_lose_probability = 0.0;
    for (const auto &[s_sum, s_prob] : s_distribution) {
      if (u_sum > s_sum) {
        s_lose_probability += s_prob;
      }
    }
    u_win_probability += u_prob * s_lose_probability;
  }

  // 保留三位小数
  return round(u_win_probability * 1000) / 1000.0;
}

int main() {
  // Add your test cases here

  std::cout << (solution(1, 3, {8}, {2, 3, 4}) == 0.255) << std::endl;
  std::cout << (solution(2, 2, {3, 4}, {3, 3}) == 0.5) << std::endl;
  std::cout << (solution(3, 1, {2, 2, 2}, {4}) == 0.844) << std::endl;

  return 0;
}