Edward 喜欢下棋,每天下班他会把一个棋子放到棋盘中空闲的位置,有一天他发现棋盘 was dominated by the chess pieces,意思就是每一行,每一列都至少有一个棋子在上面。Edward 觉得很有趣,他想知道在一个N*M的棋盘中摆成这样的情况需要的天数的期望是多少。
14年牡丹江现场赛的题目。现在看来也不算是特别难了吧?
题目主要卡手的地方我觉得在于棋子只能放在空闲的地方。首先可以想到两个状态,一个是已经放好的行数,一个是已经放好的列数。但对于这个只能放在空闲的位置的情况,这两个状态明显解决不了。于是昨天晚上在床上前想了一下,居然想通了。添加一维状态表示当前棋盘上已经放置的棋子数量。
dp[i][j][k] 表示已经在 i 行 j 列都放有棋子并且棋子总数是 k 的情况下的期望。
对于下一个要放置的棋子,有四种可能,分别是
1):当前行,当前列都有棋子。 p1 = (i*j-s)/(n*m-k)
2):当前行有棋子,当前列没有。p2 = (i*(m-j))/(n*m-k)
3):当前行没有棋子,当前列有。p3 = ((n-i)*j)/(n*m-k)
4):当前行,当前列都没有棋子。p4 = ((n-i)*(m-j))/(n*m-k)
得到转移方程:
dp[i][j][k] = p1*dp[i][j][k+1] + p2*dp[i][j+1][k+1] + p3*dp[i+1][j][k+1] + p4*dp[]i+1[j+1][k+1];
// bz一开始写的时候概率推错了,而且初始化还少写一行,心塞至极。
/***********************************************
** problem ID : zoj_3822.cpp
** create time : Sat Aug 01 10:01:01 2015
** auther name : xuelanghu
** auther blog : blog.csdn.net/xuelanghu407
**********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int N, M;
double dp[55][55][2550];
void init() {
for (int i=0; i<55; i++) {
for (int j=0; j<55; j++) {
for (int k=0; k<2550; k++) {
dp[i][j][k] = -1.0;
}
}
}
}
double DP (int a, int b, int s) {
if (a > N || b > M || s > a * b) return dp[a][b][s] = 0.0;
if (dp[a][b][s] != -1.0) return dp[a][b][s];
if (a == N && b == M) return dp[a][b][s] = 0.0;
double p1 = (a * b - s) * 1.0 / (N * M - s);
double p2 = ((N-a) * b) * 1.0 / (N * M - s);
double p3 = (a * (M-b)) * 1.0 / (N * M - s);
double p4 = ((N-a) * (M-b)) * 1.0 / (N * M - s);
double res = 1.0;
res += DP(a, b, s + 1) * p1;
res += DP(a + 1, b, s + 1) * p2;
res += DP(a, b + 1, s + 1) * p3;
res += DP(a + 1, b + 1, s + 1) * p4;
return dp[a][b][s] = res;
}
int main () {// freopen("in.txt", "r", stdin);
int T;
scanf ("%d", &T);
for (; T--; ) {
scanf("%d%d", &N, &M);
init();
double ans = DP(0, 0, 0);
printf ("%.10lf\n", ans);
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/xuelanghu407/article/details/47190545