开始做的时候无从下手,这题就是一个概率dp。很多的细节。dp[i][j]指的是在有j个人的时候Tomato排的位置为j这个状态时的概率。这个题需要考虑的就是循环的问题,第一是p1的循环,所以对p2,p3,p4的概率进行了修改使他们的和为1.然后就是每次第一个人都失败,所以对于dp[m][n]的概率是每轮的概率和相加。还有一点就是dp[i][j]=dp[i+1][j+1]*p3+dp[i+1][j]*p2;因为是一个循环所以要对这个式子进行化简。先将最开始的值求出来。我先贴一个T掉的版本,这个版本更容易理解思路。
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
double dp[2010][2010];
double p(double a,int n){
if(n==0)
return 1.0;
else{
double cnt=p(a,n/2);
if(n%2)
return cnt*cnt*a;
else
return cnt*cnt;
}
}
main(){
double p1,p2,p3,p4;
int n,m,k;
while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4)!=-1){
p2=p2/(1-p1);p3=p3/(1-p1);p4=p4/(1-p1);
memset(dp,0,sizeof(dp));
dp[m][n]=1/(1-p(p2,n));
for(int i=1;i<m;i++){
dp[i][n]=dp[m][n]*p(p2,m-i);
}
for(int i=m+1;i<=n;i++){
dp[i][n]=dp[m][n]*p(p2,n+m-i);
}
double ans=0;
for(int j=n-1;j>=1;j--){
double tmp=1-p(p2,j);
for(int i=j;i>=1;i--){
if(i==j){
int c=i-1;
for(int kk=0;kk<j;kk++){
dp[i][j]+=dp[c%j+2][j+1]*p3*p(p2,kk);
c++;
}
dp[i][j]=dp[i][j]/tmp;
}
else{
if(!(i==1 && j==1)){
dp[i][j]=(p2*(dp[i+1][j]*tmp-dp[i+1][j+1]*p3*(1-tmp)/p2)+dp[i+1][j+1]*p3)/tmp;
}
else{
dp[1][1]=(dp[2][2]*p3)/(1-p2);
}
}
if(i<=k)
ans+=dp[i][j];
//printf("%lf ",dp[i][j]);
}
// printf("\n");
}
for(int i=1;i<=k;i++){
ans+=dp[i][n];
}
printf("%.5lf\n",ans*p4);
}
}
后来通过变形,把这个式子改好了。
但是这道题还有一个坑就是p4==0的时候需要特判,因为这样我为此还WA了一次。
AC代码:
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
double dp[2010][2010];
double const eps=1e-5;
double p(double a,int n){
if(n==0)
return 1.0;
else{
double cnt=p(a,n/2);
if(n%2)
return cnt*cnt*a;
else
return cnt*cnt;
}
}
main(){
double p1,p2,p3,p4;
int n,m,k;
while(scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4)!=-1){
if(p4<eps){
printf("0.00000\n");
continue;
}
p2=p2/(1-p1);p3=p3/(1-p1);p4=p4/(1-p1);
memset(dp,0,sizeof(dp));
dp[m][n]=1/(1-p(p2,n));
for(int i=1;i<m;i++){
dp[i][n]=dp[m][n]*p(p2,m-i);
}
for(int i=m+1;i<=n;i++){
dp[i][n]=dp[m][n]*p(p2,n+m-i);
}
double ans=0;double cnt=0;
int c=n-2;
for(int kk=0;kk<n-1;kk++){
cnt+=dp[c%(n-1)+2][n]*p3*p(p2,kk);
c++;
}
for(int j=n-1;j>=1;j--){
double tmp=1-p(p2,j);
for(int i=j;i>=1;i--){
if(i==j){
dp[i][j]=cnt/tmp;
cnt=0;
cnt+=dp[i][j]*p3;
}
else{
if(!(i==1 && j==1)){
dp[i][j]=(p2*(dp[i+1][j]*tmp-dp[i+1][j+1]*p3*(1-tmp)/p2)+dp[i+1][j+1]*p3)/tmp;
}
else{
dp[1][1]=(dp[2][2]*p3)/(1-p2);
}
}
if(i<=k)
ans+=dp[i][j];
if(i!=1 && i!=j)
cnt+=dp[i][j]*p3*p(p2,i-1);
//printf("%lf ",dp[i][j]);
}
//printf("\n");
}
for(int i=1;i<=k;i++){
ans+=dp[i][n];
}
printf("%.5lf\n",ans*p4);
}
}