题意:三个多面体,面数分别为K1,K2,K3。每个面标号1,2,...,K。投掷一次,如果是a,b,c,那么把计数器设为0,反之,计数器加上(a + b + c)。如果计数器大于n,游戏结束,反之继续投掷。求投掷次数的期望值。
思路:设dp[x]为从计数器为x时开始投掷,投掷到>n的期望值。
那么方程为dp[x] = 1 + dp[0] / k1 / k2 / k3 + sigma(dp[x + i + j + k]) / k1 / k2 / k3 . (i != a j != b k != c)
这样对于每个i,dp[i] 都会由dp[0] 表示。
开一个数组记录每个dp[i] 中dp[0] 的系数,最后迭代就可解了。
我的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
const int maxn = 1505;
int n,k1,k2,k3,a,b,c;
double cnt[maxn];
double dp[maxn];
void solve(){
fill(cnt,cnt+maxn,0);
fill(dp,dp+maxn,0);
for(int x = n ; x >= 0 ; x--){
dp[x] = 1;
for(int i = 1; i <= k1 ; i++){
for(int j = 1; j <= k2 ; j++){
for(int k = 1; k <= k3; k++){
if(i == a && j == b && k == c){
cnt[x] += 1.0 / k1 / k2 / k3;
}else{
if(x + i + j + k > n) continue;
dp[x] += dp[x + i + j + k] / k1 / k2 / k3;
cnt[x] += cnt[x + i + j + k] / k1 / k2 / k3;
}
}
}
}
}
double res = dp[0] / (1 - cnt[0]);
printf("%.10f\n",res);
}
int main(){
int cas;
scanf("%d",&cas);
while(cas--){
scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
solve();
}
return 0;
}