我是靠谱客的博主 畅快斑马,最近开发中收集的这篇文章主要介绍Gym 101174 D - Dinner Bet —— 概率DP,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

This way

题意:

盒子里有n个球,一开始每个人拿出c个,记录他们的编号。
接下来每次操作:拿出d个,如果这d个中有和一开始的c个相同的,那么就标记这个球,如果某个人的c个数都被标记过了,游戏结束,问你游戏进行的次数的期望

题解:

两个数混在一起的话不好搞,如果每次都要判断的话会很麻烦,不如分成3种数:a独有的,b独有的,共有的。
它这个两个人其中的任意一个拿完了就结束了,那么顺着推的话感觉就像是一个原点发散出去的感觉,但是如果dp[i][j][k]表示a独有的拿了i个,b独有的拿了j个,共有的拿了k个的话,,不知道步数最终怎么算呢,不清楚,那么反一下,可以逆着:dp[i][j][k]表示剩下i,j,k,没拿,然后枚举每种拿了多少转移,或者反向转移(也就是从拿了往没拿转移),下面分别是两种情况,就是转移的时候有一些变化而已。
这个是正向的:没拿往拿了转移
loop表示自环的概率

sum+=com[c-i][n1]*com[c-j][n2]*com[sam-k][n3]/com[n][d]*com[n-(c-i)-(c-j)-(sam-k)][d-n1-n2-n3]*dp[i+n1][j+n2][k+n3];

c-i表示a独有的拿了c-i个,其余类似
com[n-(c-i)-(c-j)-(sam-k)][d-n1-n2-n3]表示拿了不在范围的概率

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ld long double
const ll N=55;
ld com[N][N],dp[15][15][15];
//i,j,k,not be signed
bool vis[N];
int main(){
for(int i=0;i<N;i++)
com[i][0]=com[i][i]=1;
for(int i=1;i<N;i++)
for(int j=1;j<i;j++)
com[i][j]=com[i-1][j]+com[i-1][j-1];
int n,d,c,sam=0;
cin>>n>>d>>c;
int x;
int cc=c;
for(int i=1;i<=cc;i++){
cin>>x;vis[x]=1;
}
for(int i=1;i<=cc;i++){
cin>>x;c-=vis[x],sam+=vis[x];
}
for(int i=c;~i;i--){
for(int j=c;~j;j--){
for(int k=sam;~k;k--){
if(i+k==cc||j+k==cc)continue;
ld loop=com[n-(c-i)-(c-j)-(sam-k)][d]/com[n][d];
ld sum=1;
for(int n1=0;n1<=c-i;n1++){
for(int n2=0;n2+n1<=d&&n2<=c-j;n2++){
for(int n3=0;n3+n2+n1<=d&&n3<=sam-k;n3++){
if(!n1&&!n2&&!n3)continue;
sum+=com[c-i][n1]*com[c-j][n2]*com[sam-k][n3]/com[n][d]*com[n-(c-i)-(c-j)-(sam-k)][d-n1-n2-n3]*dp[i+n1][j+n2][k+n3];
}
}
}
//if(!i&&!j&&!k)loop=0;
dp[i][j][k]=sum/(1-loop);
}
}
}
cout<<fixed<<setprecision(5)<<dp[0][0][0]<<endl;
return 0;
}

或者是拿了往没拿方向转移,也就是逆着转移:

for(int i=0;i<=c;i++){
for(int j=0;j<=c;j++){
for(int k=0;k<=sam;k++){
if(i+k==0||j+k==0)continue;
ld loop=com[n-i-j-k][d]/com[n][d];
ld sum=1;
for(int n1=0;n1<=i;n1++){
for(int n2=0;n2+n1<=d&&n2<=j;n2++){
for(int n3=0;n3+n2+n1<=d&&n3<=k;n3++){
if(!n1&&!n2&&!n3)continue;
sum+=com[i][n1]*com[j][n2]*com[k][n3]/com[n][d]*com[n-i-j-k][d-n1-n2-n3]*dp[i-n1][j-n2][k-n3];
}
}
}
dp[i][j][k]=sum/(1-loop);
}
}
}
cout<<fixed<<setprecision(5)<<dp[c][c][sam]<<endl;

最后

以上就是畅快斑马为你收集整理的Gym 101174 D - Dinner Bet —— 概率DP的全部内容,希望文章能够帮你解决Gym 101174 D - Dinner Bet —— 概率DP所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部