1. 程式人生 > >Discovering Gold(概率dp 期望入門)

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;
}