求期望次数:合成大西瓜

合成大西瓜

题意:

现在有 4 种球,分别是一级球,二级球,三级球和四级球,它们的体积都是一样的。有一个垂直的管道,上端开口,下端封底,初始管道为空,管道的宽度只能容纳一个球,管道长度是无限的。当两个一级球相邻时,就可以变成一个二级球,当两个二级球相邻时,就可以变成一个三级球,当两个三级球相邻时,就可以变成一个四级球。每次操作都会从管道上方随机放入一个一、二或三级球,概率都是三分之一。当游戏出现一个四级球的时候,就代表胜利。

现在 cccd 已经将游戏玩到一个局面了,他想知道在此局面上达到胜利所需操作的期望次数

题解:

球只能升级,大的球的前面的小球不能被用到。

所以一共就9种状态{{4}, {3, 2, 1}, {3, 2}, {3, 1}, {2, 1}, {2}, {1}, {3},{}}

给这些状态编号,我们能写出他们转移的概率。B[i][j]表示状态从i转移到j的概率。

     double b = (double)1 / 3;
     vector<vector<double>> B(9, vector<double>(9));
     B[0][0] = 1;
     B[1][0] = B[1][5] = B[1][7] = b;
     B[2][0] = B[2][1] = B[2][7] = b;
     B[3][2] = B[3][5] = B[3][7] = b;
     B[4][5] = b;
     B[4][7] = b + b;
     B[5][4] = b;
     B[5][7] = b + b;
     B[6][7] = b;
     B[6][5] = b + b;
     B[7][2] = B[7][3] = B[7][0] = b;
     B[8][5] = B[8][6] = B[8][7] = b;

我们用另一个矩阵表示当前状态在各位置的可能(当前状态在它的序号位置值为1,表示100%在这里)。

 vector<double> A(9);

矩阵A*B就是转移一次后状态转移后在各位置的可能,9个位置,每个位置的数值表示状态在当前位置的概率。

用结果迭代A,每迭代n次,表示n次操作后状态在各位置的概率。

这就是马尔科夫链,A会趋近一个固定值,这里,我们可以想象,n很大的时候,在0的位置,也就是赢的概率趋近1。

A[0]_{cnt}表示cnt次能到的概率,a_{cnt}=A[0]_{cnt}-A[0]_{cnt-1}就表示cnt次转移到达终点的概率(a_{cnt}会很快趋近于0)。

那么到达终点的期望次数为:E = \sum_{cnt=1}^{\infty} cnt \times a_{cnt}a_{cnt}会很快趋近于0,所以很快能算出来)

代码:

 
#include <iostream>
 #include <vector>
 #include <algorithm>
 #include <cmath>
 #define ll long long
 #define inf 0x3f3f3f3f
 using namespace std;
 ​
 void matrixMultiply(vector<double> &A, vector<vector<double>> &B)
 {
     int n = B.size();
     vector<double> result(n, 0);
     for (int i = 0; i < n; i++)
     {
         for (int j = 0; j < n; j++)
         {
             result[i] += A[j] * B[j][i];
         }
     }
     result.swap(A);
     return;
 }
 ​
 vector<double> A(9);
 vector<vector<double>> B(9, vector<double>(9));
 vector<vector<int>> C = {{4}, {3, 2, 1}, {3, 2}, {3, 1}, {2, 1}, {2}, {1}, {3},{}};
 double b = (double)1 / 3;
 int main(int argc, char *argv[])
 {
     // ios::sync_with_stdio(false);
     // cin.tie(0);
     B[0][0] = 1;
     B[1][0] = B[1][5] = B[1][7] = b;
     B[2][0] = B[2][1] = B[2][7] = b;
     B[3][2] = B[3][5] = B[3][7] = b;
     B[4][5] = b;
     B[4][7] = b + b;
     B[5][4] = b;
     B[5][7] = b + b;
     B[6][7] = b;
     B[6][5] = b + b;
     B[7][2] = B[7][3] = B[7][0] = b;
     B[8][5] = B[8][6] = B[8][7] = b;
     
     ll n ;
     cin>>n; 
     vector<int> a(n);
     for (int i = 0; i < n; i++)
     {
         cin>>a[i];
     }
     int l = 0, pos = 0;//l是上个位置的值,pos保存位置,这里找到最后的最大数的位置
     for (int i = n - 1; i >= 0; i--)
     {
         if (a[i] > l)
         {
             l = a[i];
             pos = i;
         }
         else
         {
             break;
         }
     }
     vector<int> now;//当前的状态
     for (int i = pos; i <= n - 1; i++)
     {
         now.push_back(a[i]);
     }
 ​
     for (int i = 0; i < 9; i++)
     {
         if (now == C[i])
         {
             A[i] = 1;//当前的状态对应的序号
         }
     }
 ​
     double ans=0;//期望
     int cnt=0;//操作次数
     double pass=0;//上一个值
     while (fabs(A[0]-1)>1e-8){
         matrixMultiply(A, B);//迭代
         cnt++;
         ans+=(A[0]-pass)*cnt;
         pass=A[0];
     }
     printf("%.8lf", ans);
     return 0;
 }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值