我们是在从后往前推 ,即我们是在用当前局推上一局
i:表示还有i次没打,a:表示上一局血量为1的还有多少个,b:2,c:3
f[i]中a,b,c考虑这一局和上一局比a,b,c的变化
double k=1/(1+a+b+c) //我们要转移状态选择每一个人物的概率(因为有一个英雄,所以+1)
int tot=a+b+c;
f[i+1][a][b][c]+=(f[i][a][b][c]+1)*k;//攻击英雄
if(a) f[i+1][a][b][c]+=f[i][a-1][b][c]*a*k;//攻击血量为1的随从,死亡
if(b)
{
if(tot<7) f[i+1][a][b][c]+=f[i][a+1][b-1][c+1]*b*k;//可以增加奴隶主
else f[i+1][a][b][c]+=f[i][a+1][b-1][c]*b*k;
}
if(c)
{
if(tot<7) f[i+1][a][b][c]+=f[i][a][b+1][c]*c*k;
else f[i+1][a][b][c]+=f[i][a][b+1][c-1]*c*k;
}
这就是期望dp的核心
嗯,也没什么好说的了,代码:
#include<cstdio>
#include<iostream>
using namespace std;
double f[60][10][10][10];
int t;
int read()
{
int num=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) num=(num<<3)+(num<<1)+(ch^48),ch=getchar();
return num*f;
}
void work()
{
for(int i=0;i<50;i++)
for(int a=0;a<=7;a++)
for(int b=0;b<=7-a;b++)
for(int c=0;c<=7-a-b;c++)
{
double k=1.0/(1+a+b+c);
int tot=a+b+c;
f[i+1][a][b][c]+=(f[i][a][b][c]+1)*k;
if(a) f[i+1][a][b][c]+=f[i][a-1][b][c]*a*k;
if(b)
{
if(tot<7) f[i+1][a][b][c]+=f[i][a+1][b-1][c+1]*b*k;
else f[i+1][a][b][c]+=f[i][a+1][b-1][c]*b*k;
}
if(c)
{
if(tot<7) f[i+1][a][b][c]+=f[i][a][b+1][c]*c*k;
else f[i+1][a][b][c]+=f[i][a][b+1][c-1]*c*k;
}
}
}
int main()
{
work();
t=read();
while(t--)
{
int k=read(),a=read(),b=read(),c=read();
printf("%.2lf\n",f[k][a][b][c]);
}
return 0;
}