题目链接:Discovering Gold - LightOJ 1030 - Virtual Judge (ppsucxtt.cn)
题意:现在有一个长度为n的黄金走廊,你可以把他理解为一个1 * n的序列。每一个位置都可以含有一定数量的黄金。最初你处于位置1。现在每个回合你掷一个6面骰子。假设掷出的数字为X,这时你的位置就会加上X,然后从新的位置收集黄金。如果当前位置加上X后的位置超出了n,则重新掷直到不超过n。当你到达第n个位置时,你就停止了你的旅程。现在已知序列,请你计算你可以收集到的黄金的预期数量。
分析:如果我们能求出经过每个位置的概率,那我们就可以直接把每个位置的概率乘以其位置上的黄金,然后总和即为收集到的黄金的期望。相信大家之前在做dp问题的时候都遇到过爬楼梯问题,每次可以爬一阶或两阶楼梯,问到达第n阶楼梯的方案数一共有多少种,这就是一个典型的dp问题,dp方程是f[n]=f[n-1]+f[n-2],而这道题就是一个对概率的dp,我们如果到达了位置i,那么所有他能到达的位置的概率都要因为他而加上1/p[i],因为他到达他所能到达的每一个位置的概率是相等的,由这个dp方程,我们就可以求得经过每一个点的概率,最后把每个点的概率乘以该点所含的黄金数量相加就得到答案了。
下面是代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=105;
double p[N];
int a[N];
int main()
{
int T;
cin>>T;
for(int o=1;o<=T;o++)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p[i]=0;
}
p[1]=1;
//用当前点的概率去更新它可以到达的点的概率
for(int i=1;i<n;i++)
{
int k=min(6,n-i);
for(int j=1;j<=k;j++)
p[i+j]+=p[i]/k;
}
double ans=0;
for(int i=1;i<=n;i++)
ans+=p[i]*a[i];
printf("Case %d: %.10f\n",o,ans);
}
return 0;
}