题外话
其实不是很清楚概率dp还有期望这种东西的求法,看来下学期的概率论必须必须要认真听惹。
———————————————————————————————————————————————————
题意:有一个N*M的棋盘,每天会在棋盘的所有未放棋子的格子中随机选择一个位置放置一个棋子,问棋盘要达到每行行列最少有一个棋子,平均需要放多少枚棋子。
dp[i][j][k]:表示用k个石子满足i行j列最少有一个石子的概率;
分四种情况,k++时:
1.这个棋子使被填过的行列数都加1;dp[i+1][j+1][k+1]+=dp[i][j][k]*(n-i)*(m-j)/(n*m-k);
//(n-i)*(m-j)这里面所有的位置 可以使i,j都加1
//下面同理
2.这个棋子使被填过的行数(i)加1;dp[i+1][j][k+1]+=dp[i][j][k]*(n-i)*j/(n*m-k);
3.这个棋子使被填过的列数(j)加1;dp[i][j+1][k+1]+=dp[i][j][k]*i*(m-j)/(n*m-k);
4.这个棋子没有增加被填的行列数(i j都不变化)dp[i][j][k+1]+=dp[i][j][k]*(i*j-k)/(n*m-k);
ans= sigma ( k * dp[N][M][k]) ( 1<=k<=N*M)
AC代码
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
double dp[55][55][2505];
int main()
{
int t;scanf("%d",&t);
int n,m;
while(t--)
{
scanf("%d%d",&n,&m);
memset(dp,0.0,sizeof(dp));
dp[1][1][1]=1.00;
/* for(int k=1;k<=n*m+1 ;k++)
{
for(int i=1;i<=n+1;i++)
{
for(int j=1;j<=m+1;j++)
{
if(i==n&&j==m||dp[i][j][k]==0) continue;
if(i+1<=n&&j+i<=m) dp[i+1][j+1][k+1]+=dp[i][j][k]*(n-i)*(m-j)/(n*m-k);
if(i+1<=n) dp[i+1][j][k+1]+=dp[i][j][k]*(n-i)*j/(n*m-k);
if(j+1<=m) dp[i][j+1][k+1]+=dp[i][j][k]*i*(m-j)/(n*m-k);
if(i*j>k) dp[i][j][k+1]+=dp[i][j][k]*(i*j-k)/(n*m-k);
}
}
}
*/
for(int k=1;k<=n*m+1 ;k++)
{
for(int i=1;i<=n+1;i++)
{
for(int j=1;j<=m+1;j++)
{
if (i==n&&j==m||dp[i][j][k]==0) continue;
if (i+1<=n) dp[i+1][j][k+1] += dp[i][j][k]*(n-i)*j/(n*m-k);
if (j+1<=m) dp[i][j+1][k+1] += dp[i][j][k]*i*(m-j)/(n*m-k);
if (i+1<=n&&j+1<=m) dp[i+1][j+1][k+1] += dp[i][j][k]*(n-i)*(m-j)/(n*m-k);
if (i*j>k) dp[i][j][k+1] += dp[i][j][k]*(i*j-k)/(n*m-k);
}
}
}
double ans=0.0;
for(int i=0; i<=n*m+1; i++){
ans+=(dp[n][m][i])*i;
}
printf("%.12lf\n",ans);
}
return 0;
我被坑惨了55555……
if的顺序写错,wa好多次,我是猪