DP学习:概率dp
1.SPOJ Favorite Dice
题意:
甩一个n面的骰子,问每一面都被甩到的次数期望是多少。
做法:
期望dp
那我们每次可能扔中已经扔过的面或者没有扔到过的面,则在第i次有2种情况:
1.扔中已经扔过的面概率:(i-1)/n,期望:E= dp(i - 1) * ((i - 1) / n)
2.扔中未扔到过的面概率:(n-(i-1)) /n,期望:E= dp(i) * ((n - (i - 1)) / n)
则状态方程:dp(i) = dp(i - 1) * ((i - 1) / n) + 1 + dp(i) * ((n - (i - 1)) / n)。
解得dp(i) = dp(i - 1) + (n / (i - 1))
点击查看代码块
/*
甩一个n面的骰子,问每一面都被甩到的次数期望是多少。
*/
#include <bits/stdc++.h>
#define ed end()
#define bg begin()
#define mp make_pair
#define pb push_back
#define v(T) vector<T>
#define all(x) x.bg,x.ed
#define newline puts("")
#define si(x) ((int)x.size())
#define rep(i,n) for(int i=1;i<=n;++i)
#define rrep(i,n) for(int i=0;i<n;++i)
#define srep(i,s,t) for(int i=s;i<=t;++i)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 1e4+10;
const int inf = 0x7f7f7f7f;
const ll inf_ll = 1ll*inf*inf;
const int Mod = 1e9+7;
const double eps = 1e-7;
double dp[maxn];
int main(){
int T;
scanf("%d",&T);
for(int _=1;_<=T;_++)
{
int n;
scanf("%d",&n);
dp[1]=1.0;
for (int i=2;i<=n;i++){
dp[i]=dp[i-1]+((double)n / (i-1.0));
}
printf("%.2f\n",dp[n]);
}
return 0;
}
2.小A买彩票
题目描述:
小A最近开始沉迷买彩票,并且希望能够通过买彩票发家致富。已知购买一张彩票需要3元,而彩票中奖的金额分别为1,2,3,4元,并且比较独特的是这个彩票中奖的各种金额都是等可能的。现在小A连续购买了n张彩票,他希望你能够告诉他至少能够不亏本的概率是多少。
做法:
看似要求概率,实则可以进行转换成求方案数:dp[i][j]表示选第i张彩票获得j利润时候的方案数。
则
\(dp[i][j] = Σdp[i-1][j-k] (1<=k<=4)\)
最后求一个j>=3*n时候的方案数除以总方案数则为答案,要记得约分化简
点击查看代码块
#include <bits/stdc++.h>
#define ed end()
#define bg begin()
#define mp make_pair
#define pb push_back
#define vv(T) v(v(T))
#define v(T) vector<T>
#define all(x) x.bg,x.ed
#define newline puts("")
#define si(x) ((int)x.size())
#define rep(i,n) for(int i=1;i<=n;++i)
#define rrep(i,n) for(int i=0;i<n;++i)
#define srep(i,s,t) for(int i=s;i<=t;++i)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 200;
const int inf = 0x7f7f7f7f;
const ll inf_ll = 1ll*inf*inf;
const int Mod = 1e9+7;
const double eps = 1e-7;
int n;
ll dp[maxn][maxn];
ll gcd(ll a,ll b){
return b == 0 ? a : gcd(b,a%b);
}
int main(){
cin>>n;
if(n==0){
puts("1/1");
return 0;
}
memset(dp,0,sizeof(dp));
rep(i,4){
dp[1][i]=1;
}
for (int i=2;i<=n;i++){
for (int j=1;j<=i*4;j++){
for (int k=1;k<=4;k++){
if(j-k>=0){
dp[i][j]+=dp[i-1][j-k];
}
}
}
}
ll cnt1,cnt2;
cnt1=cnt2=0;
for (int i=1;i<=4*n;i++){
cnt1+=dp[n][i];
if(i>=n*3) cnt2+=dp[n][i];
}
ll k = gcd(cnt1,cnt2);
printf("%lld/%lld\n",cnt2/k,cnt1/k);
return 0;
}