1. 程式人生 > >[BZOJ4832]抵制克蘇恩(概率期望DP)

[BZOJ4832]抵制克蘇恩(概率期望DP)

方法一:倒推,最常規的期望DP。f[i][a][b][c]表示還要再攻擊k次,目前三種隨從個數分別為a,b,c的期望攻擊英雄次數,直接轉移即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9
const int N=60,M=10; 10 int n,a,b,c,T; 11 double f[N][M][M][M]; 12 13 int main(){ 14 freopen("bzoj4832.in","r",stdin); 15 freopen("bzoj4832.out","w",stdout); 16 rep(i,1,50) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){ 17 int t=(a+b+c<7); 18 f[i][a][b][c]+=(f[i-1][a][b][c]+1
)/(a+b+c+1); 19 if (a) f[i][a][b][c]+=f[i-1][a-1][b][c]*a/(a+b+c+1); 20 if (b) f[i][a][b][c]+=f[i-1][a+1][b-1][c+t]*b/(a+b+c+1); 21 if (c) f[i][a][b][c]+=f[i-1][a][b+1][c-1+t]*c/(a+b+c+1); 22 } 23 for (scanf("%d",&T); T--; ) 24 scanf("%d%d%d%d",&n,&a,&b,&c),printf("
%.2lf\n",f[n][a][b][c]); 25 return 0; 26 }

方法二:用順推做期望DP,f[x]=(f[k]+w[k][x])*p[k][x],其中k是所有能到達x的狀態,w[k][x]表示這個轉移的代價(攻擊隨從時為0,攻擊英雄時為1),p[k][x]是x由k得到的概率(注意不是k轉移到x的概率)。

P(x由k得到)=P(k)*P(k轉移到x)/P(x),同時維護p和f即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=60,M=10;
10 const double eps=1e-10;
11 int n,a,b,c,T;
12 double p[N][M][M][M],f[N][M][M][M];
13 
14 int main(){
15     freopen("bzoj4832.in","r",stdin);
16     freopen("bzoj4832.out","w",stdout);
17     for (scanf("%d",&T); T--; ){
18         memset(p,0,sizeof(p)); memset(f,0,sizeof(f));
19         scanf("%d%d%d%d",&n,&a,&b,&c); p[0][a][b][c]=1; double ans=0;
20         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
21             int t=(a+b+c<7);
22             p[i+1][a-1][b][c]+=p[i][a][b][c]*a/(a+b+c+1);
23             p[i+1][a+1][b-1][c+t]+=p[i][a][b][c]*b/(a+b+c+1);
24             p[i+1][a][b+1][c-1+t]+=p[i][a][b][c]*c/(a+b+c+1);
25             p[i+1][a][b][c]+=p[i][a][b][c]/(a+b+c+1);
26         }
27         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
28             int t=(a+b+c<7); double x=f[i][a][b][c]*p[i][a][b][c];
29             if (p[i+1][a-1][b][c]>eps)
30                 f[i+1][a-1][b][c]+=x*a/((a+b+c+1)*p[i+1][a-1][b][c]);
31             if (p[i+1][a+1][b-1][c+t]>eps)
32                 f[i+1][a+1][b-1][c+t]+=x*b/((a+b+c+1)*p[i+1][a+1][b-1][c+t]);
33             if (p[i+1][a][b+1][c-1+t]>eps)
34                 f[i+1][a][b+1][c-1+t]+=x*c/((a+b+c+1)*p[i+1][a][b+1][c-1+t]);
35             if (p[i+1][a][b][c]>eps)
36                 f[i+1][a][b][c]+=(f[i][a][b][c]+1)*p[i][a][b][c]/((a+b+c+1)*p[i+1][a][b][c]);
37         }
38         rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b) ans+=f[n][a][b][c]*p[n][a][b][c];
39         printf("%.2lf\n",ans);
40     }
41     return 0;
42 }

 

方法三:同樣用順推,但這裡的f是上面的f*p,轉移時要考慮期望的定義

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=60,M=10;
10 const double eps=1e-10;
11 int n,a,b,c,T;
12 double p[N][M][M][M],f[N][M][M][M];
13 
14 int main(){
15     for (scanf("%d",&T); T--; ){
16         memset(p,0,sizeof(p)); memset(f,0,sizeof(f));
17         scanf("%d%d%d%d",&n,&a,&b,&c); p[0][a][b][c]=1; double ans=0;
18         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
19             int t=(a+b+c<7);
20             p[i+1][a-1][b][c]+=p[i][a][b][c]*a/(a+b+c+1);
21             p[i+1][a+1][b-1][c+t]+=p[i][a][b][c]*b/(a+b+c+1);
22             p[i+1][a][b+1][c-1+t]+=p[i][a][b][c]*c/(a+b+c+1);
23             p[i+1][a][b][c]+=p[i][a][b][c]/(a+b+c+1);
24         }
25         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
26             int t=(a+b+c<7);
27             if (p[i+1][a-1][b][c]>eps)
28                 f[i+1][a-1][b][c]+=f[i][a][b][c]*a/(a+b+c+1);
29             if (p[i+1][a+1][b-1][c+t]>eps)
30                 f[i+1][a+1][b-1][c+t]+=f[i][a][b][c]*b/(a+b+c+1);
31             if (p[i+1][a][b+1][c-1+t]>eps)
32                 f[i+1][a][b+1][c-1+t]+=f[i][a][b][c]*c/(a+b+c+1);
33             if (p[i+1][a][b][c]>eps)
34                 f[i+1][a][b][c]+=(f[i][a][b][c]+p[i][a][b][c])/(a+b+c+1);
35         }
36         rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b) ans+=f[n][a][b][c];
37         printf("%.2lf\n",ans);
38     }
39     return 0;
40 }