[HDOJ 4870] Rating [概率DP]

69 篇文章 0 订阅
3 篇文章 0 订阅

一个人用两个帐号参加比赛,每次他都用积分低的那个参加,参加一场比赛有p的概率让那个号的积分加一,有(1-p)的概率让那个号的积分减二。最开始两个号的积分都是0,问他有一个号的积分达到20的期望比赛次数。

定义状态dp[k]为只使用一个帐号,从积分为k到积分为k+1的期望比赛次数,则dp[k]=1+p*0+(1-p)*(dp[k-2]+dp[k-1]+dp[k]),k>=2,dp[1]=1+p*0+(1-p)*(dp[0]+dp[1]),dp[0]=1+p*0+(1-p)*(dp[0])。

因为他使用一个帐号比赛,如果输了就会一直用这个帐号,直到积分涨回去比原来还高为止。

所以ans=dp[0]*2+dp[1]*2+...+dp[18]*2+dp[19]

#include <cstdio>
#include <cstring>
#include <cmath>

double dp[20];
double p;

int main() {
	int i,j;
	double ans;
	while (scanf("%lf",&p)!=EOF) {
		dp[0]=1/p;
		dp[1]=(1+(1-p)*dp[0])/p;
		for (i=2;i<20;i++) {
			dp[i]=(1+(1-p)*(dp[i-2]+dp[i-1]))/p;
		}
		ans=dp[19];
		for (i=0;i<19;i++) {
			ans+=dp[i]+dp[i];
		}
		printf("%.8lf\n",ans);
	}
	return 0;
}

附上一个过不去的代码..

定义状态dp[i][j]表示两个号分别有i和j的积分,其中i<=j。带入消元法。

事实证明因为除法次数太多,所以丢精度丢的太厉害...所以跪了...

#include <cstdio>
#include <cstring>

long double p,p1;
long double dp[201][201];
long double a[201],b[201],c[201];
long double x,y;

void calxy(long double a3,long double b3,long double c3,long double a4,long double b4,long double c4,long double a5,long double b5,long double c5) {
    long double a1=a3-a4,a2=a3-a5;
    long double b1=b3-b4,b2=b3-b5;
    long double c1=c3-c4,c2=c3-c5;
    //printf("%Lf %Lf\n",a1*b2-a2*b1,b1*a2-b2*a1);
    x=(c2*b1-c1*b2)/(a1*b2-a2*b1);
    y=(c2*a1-c1*a2)/(b1*a2-b2*a1);
}

int main() {
    int i,j;
    for (i=0;i<=20;i++) {
        dp[i][20]=0;
    }
    while (scanf("%Lf",&p)!=EOF) {
        if (p==1) printf("39.000000\n");
        else {
            p1=1-p;
            for (j=19;j>=2;j--) {
                a[j]=0;b[j]=1;c[j]=0;
                a[j-1]=1;b[j-1]=0;c[j-1]=0;
                a[j-2]=0;b[j-2]=1/p1;c[j-2]=(-1-p*dp[j][j+1])/p1;
                for (i=j-3;i>=0;i--) {
                    a[i]=(a[i+2]-p*a[i+3])/p1;
                    b[i]=(b[i+2]-p*b[i+3])/p1;
                    c[i]=(c[i+2]-p*c[i+3]-1)/p1;
                }
                calxy(a[0],b[0],c[0],(a[1]-p*a[2])/p1,(b[1]-p*b[2])/p1,(c[1]-p*c[2]-1)/p1,a[1],b[1],c[1]+1/p);
                dp[j][j]=y;
                dp[j-1][j]=x;
                dp[j-2][j]=(dp[j][j]-1-p*dp[j][j+1])/p1;
                for (i=j-3;i>=0;i--) {
                    dp[i][j]=(dp[i+2][j]-1-p*dp[i+3][j])/p1;
                }
            }
            dp[1][1]=1/p+dp[1][2]+p1/p/p;
            dp[0][1]=1/p+dp[1][1];
            dp[0][0]=1/p+dp[0][1];
            printf("%.8Lf\n",dp[0][0]);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值