2021-05-26

抽卡毕业概率(转盘式)

模拟的是卡池上新,毕业指所有新卡至少抽到一张。
因为只在乎抽新卡,所以做成转盘式,只考虑随机数落到了特定小区间内,落在外面一律忽略就行。
其它抽卡模型:共享卡池、卡表、稀有度分层
相关机制:水位、保底、氪度

/*
文件名:random.cpp
作者:SXBKDpiang
描述:模拟抽卡
修改时间:2020.08.13
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;

//基于大数定律,以多次实验排除偶然误差,计算卡池毕业的概率


struct Card         //每个结构体表示一张新卡,左右区间可以想象成转盘抽奖,随机到区间里表示抽到了
{
    int left;       //左区间
    int right;      //右区间
    int flag=0;     //该卡是否被抽到,0表示没有,1表示抽到
};

int main()
{
    const int ExperimentTimes=20000;            //实验次数,即人数
    const int Lowest=0.1;                       //概率最小的卡的概率,一般都是0.1的倍数吧
    const int Total=1000;                       //放大后的总区间,100/Lowest

    int PresentNumber=0;                        //记录生成的随机数
    int graduate[ExperimentTimes]={0};          //c[i]记录一共用了i抽毕业的人数

    srand((unsigned)time(NULL));                //随机数


    /*
    设计判定条件
    */
    int CardNumber=0;                   //新卡数量
    cout<<"请输入本次要抽的卡的数量:";
    cin>>CardNumber;

    struct Card card[CardNumber];       //C99后可以这么开数组了

    cout<<"请输入各个卡的概率:";
    int number=0;                       //划分每张卡的判定范围
    for(int i=0;i<CardNumber;i++)       //第一张卡的区间是0-np,意为随机到这个区间时是抽到了第一张卡
    {
        float p;                        //每张卡的概率
        cin>>p;
        card[i].left=number;
        number=number+p*2;              //同比例放大到整数
        card[i].right=number;
        number++;
    }


    for(int z=0;z<ExperimentTimes;z++)  //多次实验找到普遍规律
    {
        //换人时重置flag
        for(int i=0;i<CardNumber;i++)
            card[i].flag=0;

        for(int i=1;i<=100*Total;i++)   //保证单人抽卡足够多,一定能毕业,只是10连或是1000连的区别
        {

            PresentNumber = rand()%Total;        //这一次抽到了第PresentNumber张卡
            for(int n=0;n<CardNumber;n++)
                if(card[n].left<=PresentNumber&&card[n].right>=PresentNumber)
                    card[n].flag=1;

            //判断是否毕业
            int Count=0;
            for(int n=0;n<CardNumber;n++)
            {
                if(card[n].flag==1)
                    Count++;
            }
            if(Count==CardNumber)
            {
                graduate[i]++;          //第m个人为i抽毕业
                break;                  //毕业了就换下一个人
            }
        }
    }

    for(int i=0;i<200;i++)
    {
        for(int j=0;j<10;j++)
        {
            cout<<10*i+j<<":"<<graduate[10*i+j]<<" ";
        }
        cout<<endl;
    }
    /*
    根据给定的预计排位(0-1)计算对应的抽卡数
    */
    float percent;                      //比多少人非,0~1
    float C=0;                          //C=i抽内毕业人数
    cout<<"比多少人非0-1"<<endl;
    cin>>percent;
    //percent=percent*ExperimentTimes;    //比你欧的人数

    //最欧的人抽了Search次
    int Search=0;
    while(graduate[Search]==0)
        Search++;

    for(int i=Search;i<ExperimentTimes;i++)
    {
        if(C/ExperimentTimes<percent)
            C+=graduate[i];             //C=i抽内毕业人数
        else
        {
            cout<<i<<"抽"<<endl;
            break;
        }
    }

    /*
    根据给的抽卡次数计算毕业概率
    */
    int DrawTimes;
    float Percent=0;
    cout<<"多少抽毕业"<<endl;
    cin>>DrawTimes;
    for(int i=0;i<DrawTimes;i++)
        Percent=Percent+graduate[i];
    cout<<Percent/ExperimentTimes<<endl;

    return 0;
}

上一篇:题目集7~9的总结


下一篇:信用卡业务产品部门KPI与工作模式