[BZOJ4832]抵制克蘇恩(概率期望DP)
阿新 • • 發佈:2018-11-09
方法一:倒推,最常規的期望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 9const 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 }