【组队赛#8】BNU 1084 Expected Allowance (母函数)

 【题目链接】click here~~  

题目大意】给出一个n个骰子,每个骰子有m个面,给出一个削减值k,投掷一次,所有的骰子点数和要减去k,如果减去的值小于1,则得到的钱也至少是1;要求出他能得到钱的期望值

解题思路】母函数!!,关键在于理解题意思路:(每个点数出现的概率要计算) 具体看代码吧

母函数:

#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
double c1[100005],c2[100005];
int main()
{
    int i,j,k,n,m,p;
    double sum;
    while(cin>>n>>m>>p)
    {
        if(n==0&&m==0&&p==0) break;
        sum=0;
        for(i=1; i<=m; i++){//初始化
            c1[i]=1;        //系数为1
            c2[i]=0;
        }
        for(i=1; i<n; i++){
            for(j=1; j<=m*i; j++)//第i个骰子投掷出m面的可能数
                for(k=1; k<=m; k++){//总共m面
                    c2[j+k]+=c1[j];
                }
            memcpy(c1,c2,sizeof(c2));
            memset(c2,0,sizeof(c2));
        }
//        for(int i=1;i<=m;i++)
//        {
//            cout<<c1[i]<<" "<<c2[i]<<endl;
//        }
        for(int i=n; i<=n*m; i++){//n个骰子,每个m面,最小点数为n,最大点数为n*m
            if(i>p)
                sum+=c1[i]*(double)(i-p);
            else
                sum+=c1[i];
        }
//          cout<<"#"<<sum<<"#"<<endl;
        printf("%.8lf\n",sum/pow(m,n));
    }
    return 0;
}
当时比赛最后十几分钟,突然想到一个递推的思路,大致思路是这样:每次从1到m面搜一遍,找出出现1到n*m面的所有可能数,当以骰子个数为0 时结束,且每次计算ans的值

dfs:

#include <bits/stdc++.h>
using namespace std;
double pow(double n,double m)
{
    double res=1;
    for(int i=1; i<=n; i++)
        res*=(m);
    return res;
}
double  ans;
double n,m,k;
double sum;
void dfs(int a,int b)
{
    if(a==0)
    {
        ans+=(b-k<1?1:(b-k));
        return;
    }
    for(int i=1;i<=m;i++)
    {
        dfs(a-1,b+i);
    }
}
int main()
{
    while(cin>>n>>m>>k)
    {
        ans=0;
        if(n==0&&m==0&&k==0) break;
        dfs(n,0);
        //printf("%lf\n",ans);
        double ans2=pow(n,m);
        double result=(ans/ans2);
        printf("%.8lf\n",result);
    }
    return 0;
}

你可能感兴趣的:(ACM,母函数)