例题:
题意:
n个俱乐部,m个奖牌,每个俱乐部可以拿这m个奖牌之一作为该俱乐部游戏的奖励。现在有一些人来参加游戏,游戏终止条件是所有奖牌都被收集,问你最小游戏次数的期望值是多少
思路:
1、我们可以发现在n个俱乐部均分m块奖牌的时候,会让游戏次数最小(为什么发现我也不知道)
2、但肯定有不能均分的,这时候我们就把所有的奖牌分为两个大类
a:不能被n个俱乐部均分的
b:能被n个俱乐部均分的
int a = n % m, b = m - a;
则个数分别为
int ca = (n + m - 1) / m, cb = n / m; // cnt
设dp[i][j] 表示差 i 个第一类奖牌和 j 个第二类奖牌所需要的期望次数,dp[0][0] = 0
选取到新的奖牌的总概率 s 为 i * ca + j * cb;
再从总概率里分出选出a的概率和选出b的概率
long double s = i * ca + j * cb;
long double p1 = 1.0 * i * ca / s;
long double p2 = 1.0 * j * cb / s;
有p1的概率从dp[i - 1][j] 传递, dp[i][j] += dp[i - 1][j]。需要主义的是 i 要大于零
if (i) dp[i][j] += (p1) * dp[i - 1][j];
p2同理
贴个总代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 2e6 + 10, mod = 998244353, INF = 0x3f3f3f3f;
long double dp[5010][5010];
void solve() {
int n, m;
cin >> n >> m;
int a = n % m, b = m - a;
int ca = (n + m - 1) / m, cb = n / m; // cnt
dp[0][0] = 0;
for (int i = 0; i <= a; i ++) {
for (int j = 0; j <= b; j ++) {
long double s = i * ca + j * cb;
long double p1 = 1.0 * i * ca / s;
long double p2 = 1.0 * j * cb / s;
if (!i && !j) continue;
dp[i][j] += n / s;
if (i) dp[i][j] += (p1) * dp[i - 1][j];
if (j) dp[i][j] += (p2) * dp[i][j - 1];
}
}
cout << fixed << setprecision(10) << dp[a][b];
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
solve();
return 0;
}
贴个记忆化搜索的
#include<bits/stdc++.h>
using namespace std;
int n,m;
long double dp[5002][5002];
int x;
int y;
int B;
int A;
long double dfs(int a,int b) {
/*
A:B 已经有了a:b个
*/
if(dp[a][b]!=-1) {
return dp[a][b];
}
if(a>A || b>B) {
return 0;
}
//有用的个数=剩下没拿的部分
long double s= (A-a)*x + (B-b)*(x+1);
long double ans=0;
//两种转移的概率
long double p1= (long double)(A-a)*x/s;
long double p2= (long double)(B-b)*(x+1)/s;
//两种本身的期望 + 转移的期望步数1/p (p=n/s)
//这里其实应该更具体,是a-1本身的期望 + a-1转移的期望步数*p1。只是p1+p2==1所以最后直接+n/s
ans+=( dfs(a+1,b) ) * p1;
ans+=( dfs(a,b+1) ) * p2;
ans+=(long double) n/s;
return dp[a][b]=ans;
}
void solve() {
for(int i=0;i<=5000;i++) {
for(int j=0;j<=5000;j++) {
dp[i][j]=-1;
}
}
cin>>n>>m;
/*
两种,数量为a , b <--> x , x+1
*/
x=n/m;
y=n/m+1;
B=n%m;
A=m-n%m;
dp[A][B]=0;
long double ans=dfs(0,0);
cout<<fixed<<setprecision(12)<<ans;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while(t--)
solve();
}
其他例题: