【题目链接】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; }