对N*M的棋盘,问满足行至少一个棋子,列至少一个棋子的步数概率。
对每个状态:来自四个不同状态
位置是固定的,所以不能在一个位置上多次,于是我们至少需要3维dp
而且50*50相当小
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const ll mod=998244353;
const int maxn=2500;
double dp[55][55][maxn+5];//用i行,j列,使用k步 离结束还需要的期望天数
int main(){
int n,m,t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
mem(dp,0); //最后的n,m,k(任意多)时候,离结束的天数是0天(dp[n][m][maxn+5])
for(int i=n;i>=0;i--){
for(int j=m;j>=0;j--){
if(i==n&&j==m)continue;
for(int k=i*j;k>=min(i,j);k--){//空行(n-i) 空列(m-j) 走k步时(限定在i*j步里,限定必须至少(min(i,j)))
//总区域i*j>=k才符合实际条件
//概率就是 (满足什么条件我需要走的总方案) / (当前我可以走的所有方案)
if(i*j>=k+1)dp[i][j][k]+=(1+dp[i][j][k+1])*((double)(i*j-k)/(double)(n*m-k));//从i,j,k到i,j,k+1的转移
if((i+1)*j>=k+1)dp[i][j][k]+=(1+dp[i+1][j][k+1])*((double)((n-i)*j)/(double)(n*m-k));//i,j,k->i+1,j,k+1
if((j+1)*i>=k+1)dp[i][j][k]+=(1+dp[i][j+1][k+1])*((double)((m-j)*i)/(double)(n*m-k));//i,j,k->i,j+1,k+1
if((i+1)*(j+1)>=k+1)dp[i][j][k]+=(1+dp[i+1][j+1][k+1])*((double)((n-i)*(m-j))/(double)(n*m-k));//i,j,k->i+1,j+1,k+1
}
}
}
printf("%.9f\n",dp[0][0][0]);
}
return 0;
}