zoj 3822 Domination (概率dp 天数期望)

题目链接

参考博客:http://blog.csdn.net/napoleon_acm/article/details/40020297

题意:给定n*m的空棋盘

每一次在上面选择一个空的位置放置一枚棋子,直至每一行每一列都至少有一个棋子,求放置次数的期望

分析:

dp[i][j][k] 表示当前用了<=k个chess ,覆盖了i行j列(i*j的格子 每行至少一个,每列至少一个)的概率。

dp[i][j][k] 由 dp[i][j][k-1] , dp[i-1][j][k-1], dp[i][j-1][k-1], dp[i-1][j-1][k-1]得到,分别表示 添加的新的一个chess, 不覆盖新的行列, 只新覆盖一行, 只新覆盖一列, 同时新覆盖一行和一列,得到dp[i][j][k]。
递推时, 每个概率 * (可以覆盖的点数/剩余所有的空点数) 相加得到[i][j][k].

ans += (dp[n][m][i] - dp[n][m][i-1])* i;  (i = [1, n*m])

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #define LL __int64
 8 const int maxn = 50+10;
 9 using namespace std;
10 double d[maxn][maxn][2600];
11 
12 int main()
13 {
14     double ans;
15     int t, i, j, k, n, m;
16     cin>>t;
17     while(t--)
18     {
19         cin>>n>>m;
20         memset(d, 0, sizeof(d));
21         d[0][0][0] = 1;
22         for(i = 1; i <= n; i++)
23         for(j = 1; j <= m; j++)
24         for(k = 1; k <= n*m; k++)
25         {
26             int sum = n*m-k+1;
27             d[i][j][k] = d[i][j][k-1]*((i*j-k+1)*1.0/sum*1.0)+  //因为这里还加上了已经覆盖了i行j列的概率,所以dp[i][j][k] 表示当前用了<=k个chess ,覆盖了i行j列(i*j的格子 每行至少一个,每列至少一个)的概率。
28             d[i-1][j][k-1]*(j*(n-i+1)*1.0/sum*1.0)+
29             d[i][j-1][k-1]*(i*(m-j+1)*1.0/sum*1.0)+
30             d[i-1][j-1][k-1]*((n-i+1)*(m-j+1)*1.0/sum*1.0);
31         }
32         ans = 0;
33         for(i = 1; i <= n*m; i++)
34         ans += (d[n][m][i]-d[n][m][i-1])*i;  //减去表示用i个棋子覆盖的概率。
35 
36         printf("%.12lf\n", ans);
37     }
38     return 0;
39 }

 

做了后一道概率dp,发现也可以用期望你逆推的方法。

可参照博客:http://blog.csdn.net/smz436487/article/details/40049189

初始化:dp[i][n][m]=0;(0<=i<=n*m)

dp[0][0][0]就是答案。

2维的没办法描述每种状态下的概率

代码:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 double dp[2505][55][55];
 6 int main()
 7 {
 8     int t,n,m;
 9     scanf("%d",&t);
10     while(t--){
11         scanf("%d%d",&n,&m);
12         memset(dp,0,sizeof(dp));
13         for(int i=n*m-1;i>=0;i--){
14             for(int j=n;j>=0;j--){
15                 for(int k=m;k>=0;k--){
16                     if(j==n&&k==m)continue;
17                     if(j*k<i)continue;
18                     double p1,p2,p3,p4;
19                     p1=1.0*(j*k-i)/(n*m-i);
20                     p2=1.0*(n-j)*k/(n*m-i);
21                     p3=1.0*(m-k)*j/(n*m-i);
22                     p4=1.0*(n-j)*(m-k)/(n*m-i);
23                     dp[i][j][k]=dp[i+1][j][k]*p1+dp[i+1][j+1][k]*p2+dp[i+1][j][k+1]*p3+dp[i+1][j+1][k+1]*p4+1;
24                 }
25             }
26         }
27         printf("%.10lf\n",dp[0][0][0]);
28     }
29     return 0;
30 }

 

posted @ 2014-10-13 20:52  水门  阅读(173)  评论(0编辑  收藏  举报