ZOJ--3329(概率DP,推导)
2015-01-03 12:34:02
思路:这题是概率DP,公式不好推.....一定要细心。(晚上推到凌晨,早上起来再推终于过了.....I am so ruo!QAQ)(深深地感觉到自己的方法比网上的麻烦....)
用dp[i]表示当前计数器的值为 i ,还需要掷多少次(期望值)使得游戏结束,那么转移方程是不难列出来的:dp[i] = Sigma(dp[i + j] + 1.0) / total + dp[0] / total,(3<=j<=K1*K2*K3,total = K1*K2*K3),发现每个dp[i]都会衍生出一个含dp[0]的项。
再详细点:如果我们要算4 2 2 2 1 1 1
dp[0] = (3 * (dp[4] + 1) + 3 * (dp[5] + 1) + (dp[6] + 1)) / total + (dp[0] + 1) / total(没有dp[3],因为掷到三个1的话,计数器置零)
dp[4] = (3 * (dp[8] + 1) + 3 * (dp[9] + 1) + (dp[10] + 1)) / total + (dp[0] + 1) / total
因为 : dp[5] ~ dp[10] = 0
所以: dp[0] = (3 * (dp[4] + 1) + 4) / total + (dp[0] + 1) / total
dp[4] = (3 + 3 + 1) / total + (dp[0] + 1) / total
--> dp[0] = 【3 *(7 / total + (dp[0] + 1) / total + 1) + 4】/ total + (dp[0] + 1) /total
发现每一个dp的表达式中都有(dp[0] + 1)这一项,那么我们可以把dp表达式写成dp[i] = A[i] * (dp[0] + 1)+ B[i]
而A[i]可以由A[i + j](1<=j<=total)求出,B同理....那么可以用记忆化搜索解决。
由:A[i] = Sigma(A[i + j] + 1) / total , B[i] = (Sigma(B[i + j]) + 1) / total(这个B不太好理解....其实i+j中的A[i+j]代到i中后(A[i + j] * (dp[0] + 1) + 1) / total,会产生1 / total,应记入B[i])
那么:dp[0] = (A[0] + B[0]) / (1.0 - B[0])
(当然也可以用递推啦~)
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 #define MP(a,b) make_pair(a,b) 8 typedef pair<long double,long double> pdd; 9 const int INF = (1 << 30) - 1; 10 11 int T,n,K1,K2,K3,a,b,c; 12 long double A[550],B[550],total; 13 14 void Solve(int p){ 15 if(A[p] || p > n) return; 16 long double tmp = 0.0,res = 0.0; 17 for(int i = 1; i <= K1; ++i){ 18 for(int j = 1; j <= K2; ++j){ 19 for(int k = 1; k <= K3; ++k){ 20 if(i == a && j == b && k == c) continue; 21 Solve(p + i + j + k); 22 res += A[p + i + j + k] + 1.0; 23 tmp += B[p + i + j + k]; 24 } 25 } 26 } 27 A[p] = res / total; 28 B[p] = (tmp + 1.0) / total; 29 } 30 31 int main(){ 32 scanf("%d",&T); 33 while(T--){ 34 scanf("%d%d%d%d%d%d%d",&n,&K1,&K2,&K3,&a,&b,&c); 35 memset(A,0,sizeof(A)); 36 memset(B,0,sizeof(B)); 37 total = (long double)K1 * K2 * K3; 38 Solve(0); 39 printf("%.15Lf\n",(A[0] + B[0]) / (1.0 - B[0])); 40 } 41 return 0; 42 }