LightOJ1030 B - Discovering Gold(概率dp 期望入门)

题意

有一排洞穴,你在第一个洞穴,可以获得该洞穴的黄金,然后掷标有1-6的骰子,

是几就往下走几步,并得到该洞穴的黄金。

当离终点小于6步且不合法时就重掷直到合法为止。

求起点出发的黄金的期望。

题解

概率dp入门题。

考虑到自己dp比较菜,概率dp更菜,就做一个总结一个吧。

就是你在这点的期望,等于这个点的黄金数,加上你能走到所有的所有合法点的期望的平均。

那我能走到的所有合法点期望怎么求?

显然是从后往前dp,或者递归搜索。

代码

#include <iostream>
#include <algorithm> 
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <bitset> 
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
double dp[105];//dp[i]表示从i点出发到n点的期望 
int main()
{
	int t;
	sci(t);
	rep(k,1,t)
	{
		mem(dp,0);
		int n;
		sci(n);
		rep(i,0,n-1)scanf("%lf",&dp[i]);
		per(i,n-2,0)
		{
			int step=min(6,(n-1-i));//step为可以向前走的步数的最大值 
			rep(j,1,step)//j为实际往前走的步数 
			{
				dp[i]+=dp[i+j]/step;//有1/6的概率走到i+step获得i+step的期望
				//注意如果step<6比如说step=4,这里会重复投骰子直至合法,故走到以后四个点的概率均为1/4
				//用回溯的方法 将未来没有走到的点的期望都累加到前面的点上 
			} 
		}
		printf("Case %d: %.7lf\n",k,dp[0]); 
	}
   	return 0;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/82823273