【XSY1594】棋盘控制 概率DP

题目描述

  给你一个\(n\times m\)的棋盘,每次随机在棋盘上放一个国际象棋中的车,不能和以前放的重叠。每个车可以控制当前行和当前列。当所有行和所有列都被控制时结束游戏。问你结束时期望放了多少个车。

  注意:结束的条件是所有行和所有列都被控制,而不是所有格子都被控制。

  \(n,m\leq 50\)

题解

  简单DP

  \(f_{i,j,k}\)表示放了\(k\)个车后控制了\(i\)\(j\)列的概率

\[f_{i,j,k}=\frac{f_{i,j,k-1}\times(ij-(k-1))+f_{i,j-1,k-1}\times i(m-j+1)+f_{i-1,j,k-1}\times j(n-i+1)+f_{i-1,j-1,k-1}\times(n-i+1)(m-j+1)}{nm-k+1} \]

  答案是

\[\sum_{i=1}^{nm}i(f_{n,m,i}-f_{n,m,i-1}) \]

  弄个滚动数组搞一下

  时间复杂度:\(O(n^4)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
double f[2][60][60];
void solve()
{
	double ans=0;
	int n,m;
	scanf("%d%d",&n,&m);
	memset(f,0,sizeof f);
	int i,j,k;
	f[0][0][0]=1;
	int t=0;
	for(k=1;k<=n*m;k++)
	{
		t^=1;
		double now=1./(n*m-k+1);
		memset(f[t],0,sizeof f[t]);
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
				f[t][i][j]=(f[t^1][i][j]*(i*j-k+1)+f[t^1][i-1][j]*(n-i+1)*j+f[t^1][i][j-1]*i*(m-j+1)+f[t^1][i-1][j-1]*(n-i+1)*(m-j+1))*now;
		ans+=k*(f[t][n][m]-f[t^1][n][m]);
	}
	printf("%.10lf\n",ans);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
		solve();
	return 0;
}
posted @ 2018-03-05 21:03  ywwyww  阅读(179)  评论(0编辑  收藏  举报