关键在于找递推关系
POJ2096
题意:
一个软件有s个子系统,会产生n种bug
一个人每天发现一个bug,这个bug属于一个子系统,属于一种分类
每个bug属于某个子系统的概率是1/s,属于某种分类的概率是1/n
问发现n种bug,每个子系统都发现bug的天数的期望。
递推式:
dp[i][j]表示发现i个bug输入j个子系统的期望:
dp[i][j]= i/n * j/s dp[i][j] + i/n (s-j)/s dp[i+1][j] +(n-i)j/sdp[i+!][j] + (n-i)/n (s-j)/s *dp[i+1][j] +1
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
typedef long long ll;
double dp[1005][1005];
int main(){
int n,s;
while(scanf("%d%d",&n,&s)!=EOF){
dp[n][s]=0;
for(int i=n;i>=0;i--){
for(int j=s;j>=0;j--){
if(i==n&&j==s) continue;
dp[i][j] = (n*s+i*(s-j)*dp[i][j+1]+(n-i)*j*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1])/(n*s-i*j);
}
}
printf("%.4f\n",dp[0][0]);
}
return 0;
}
HDU 4405
题意:在一个1×n的格子上掷色子,从0点出发,掷了多少前进几步,同时有些格点直接相连,即若a,b相连,当落到a点时直接飞向b点。求走到n或超出n期望掷色子次数
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
typedef long long ll;
double dp[100005];
int id[100005];
int main(){
int n,s;
while(scanf("%d%d",&n,&s)!=EOF){
if(n==0&s==0) break;
memset(id,0,sizeof(id));
memset(dp,0,sizeof(dp));
for(int i=1;i<=s;i++){
int x,y;
scanf("%d%d",&x,&y);
id[x]=y;
}
for(int i=n-1;i>=0;i--){
if(id[i]!=0) dp[i]=dp[id[i]];
else{
for(int j=1;j<=6;j++)
dp[i]+=dp[i+j]/6.0;
dp[i]+=1;
}
}
printf("%.4f\n",dp[0]);
}
return 0;
}
题意:有n个盒子,每个盒子里装有礼物,有m个人,然后每个人都会拿盒子,如果盒子里有礼物,就把礼物拿走,盒子依然放回去。求礼物个数的期望。
方程:dp[i]=1.0-dp[i+1]/n+dp[i+1];
SGU 495
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
typedef long long ll;
double dp[100005];
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
dp[m]=1.0;
for(int i=m-1;i>=1;i--)
dp[i]=1.0-dp[i+1]/n+dp[i+1];
printf("%.10f\n",dp[1]);
}
return 0;
}
逆向考虑,转自链接
#include <iostream>
#include <algorithm
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
double p = (double)(n-1)/n;
double ans = n - n*pow(p, m);
printf("%.10lf\n", ans);
}
return 0;
}