ZOJ 3822(求期望)
Domination
Time Limit: 8 Seconds Memory Limit: 131072 KB Special Judge
Edward is the headmaster of Marjar University. He is enthusiastic about chess and often plays chess with his friends. What's more, he bought a large decorative chessboard with N rows and M columns.
Every day after work, Edward will place a chess piece on a random empty cell. A few days later, he found the chessboard was dominated by the chess pieces. That means there is at least one chess piece in every row. Also, there is at least one chess piece in every column.
"That's interesting!" Edward said. He wants to know the expectation number of days to make an empty chessboard of N × M dominated. Please write a program to help him.
Input
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
There are only two integers N and M (1 <= N, M <= 50).
Output
For each test case, output the expectation number of days.
Any solution with a relative or absolute error of at most 10-8 will be accepted.
Sample Input
2
1 3
2 2
Sample Output
3.000000000000
2.666666666667
Author: JIANG, Kai
Source: The 2014 ACM-ICPC Asia Mudanjiang Regional Contest
做了这么多概率dp,结果这道还是没做出来,心情已经不能用郁闷二字来形容了。。。
一、直接求期望
首先是状态的问题,一直在用二维,其实在算概率的时候就应该意识到二维的概率好难算,数据又是50的,很明显要用三维啊!真是笨死了!
dp[i][j][k]代表走了k步,已经有i行,j列安放了棋子。
接下来就是算概率的问题
很明显有四种可转移状态:
1、dp[i][j][k+1]表示走完k+1步,仍是有i行,j列安放了棋子。即安放的第k+1个棋子在i,j所占据的区域,概率为 (i * j - k) / (n * m - k);
2、dp[i][j+1][k+1]表示走完k+1步,有i行,j + 1列安放了棋子。即安放的第k+1个棋子在i行中但不在j列,概率为 i * (m - j) / (n * m - k);
3、dp[i+1][j][k+1]表示走完k+1步,有i + 1行,j列安放了棋子。即安放的第k+1个棋子在j列中但不在i行,概率为 (n - i) * j / (n * m - k);
4、dp[i+1][j+1][k+1]表示走完k+1步,有i + 1行,j + 1列安放了棋子。即安放的第k+1个棋子既不在j列中也不在i行,概率为 (n - i) * (m - j) / (n * m - k);
然后是初始化问题
当i == n && j == m时候,dp[i][j][k] = 0;
无意义的状态全部初始为零,没有影响。
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
#define ll long long
#define _cle(m, a) memset(m, a, sizeof(m))
#define repu(i, a, b) for(int i = a; i < b; i++)
#define repd(i, a, b) for(int i = b; i >= a; i--)
#define sfi(n) scanf("%d", &n)
#define sfl(n) scanf("%lld", &n)
#define pfi(n) printf("%d\n", n)
#define pfl(n) printf("%lld\n", n)
#define MAXN 55
double dp[MAXN][MAXN][MAXN * MAXN]; int main()
{
int T;
sfi(T);
while(T--)
{
int n, m;
sfi(n), sfi(m);
_cle(dp, );
for(int i = n; i >= ; i--)
for(int j = m; j >= ; j--)
for(int k = i * j; k >= max(i, j); k--)
{
if(n == i && j == m) continue;
dp[i][j][k] += (dp[i][j][k + ] + 1.0) * 1.0 * (i * j - k);
dp[i][j][k] += (dp[i][j + ][k + ] + 1.0) * 1.0 * (i * (m - j));
dp[i][j][k] += (dp[i + ][j][k + ] + 1.0) * 1.0 * (j * (n - i));
dp[i][j][k] += (dp[i + ][j + ][k + ] + 1.0) * 1.0 * ((n - i) * (m - j));
dp[i][j][k] = dp[i][j][k] / (1.0 * (n * m - k));
//printf("%d %d %d : %.12lf\n", i, j, k, dp[i][j][k]);
}
printf("%.12lf\n", dp[][][]);
}
return ;
}
二、先求概率,再求期望
dp[i][j][k]表示放k个棋子达到有i行,j列安放了棋子的概率。
这里有一大误区,就是开始我和我队友都搞错了,结果还以为自己是算的不对,其实是思考错了,就是在算期望是应只考虑真正起作用的棋子,eg:
2 2
dp[2][2][3] = 1, dp[2][2][4] = 1;
其实在放第四颗棋子时就已经必然为两行两列,第四颗棋子已不起作用,放与不放无关痛痒,所以,放第k颗棋子的概率为:
dp[i][j][k] - dp[i][j][k - 1];
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
#define ll long long
#define _cle(m, a) memset(m, a, sizeof(m))
#define repu(i, a, b) for(int i = a; i < b; i++)
#define repd(i, a, b) for(int i = b; i >= a; i--)
#define sfi(n) scanf("%d", &n)
#define sfl(n) scanf("%lld", &n)
#define pfi(n) printf("%d\n", n)
#define pfl(n) printf("%lld\n", n)
#define MAXN 55
double dp[MAXN][MAXN][MAXN * MAXN]; int main()
{
int T;
sfi(T);
while(T--)
{
int n, m;
sfi(n), sfi(m);
_cle(dp, );
dp[][][] = 1.0;
repu(i, , n + )
repu(j, , m + )
repu(k, max(i, j), i * j + )
{
if(k < ) continue;
dp[i][j][k] += dp[i][j][k - ] * 1.0 * (i * j - k + );
dp[i][j][k] += dp[i - ][j][k - ] * 1.0 * ((n - i + ) * j);
dp[i][j][k] += dp[i][j - ][k - ] * 1.0 * (i * (m - j + ));
dp[i][j][k] += dp[i - ][j - ][k - ] * 1.0 * ((n - i + ) * (m - j + ));
dp[i][j][k] /= (1.0 * (n * m - k + ));
//printf("%d %d %d : %.12lf\n", i, j, k, dp[i][j][k]);
}
double ans = 0.0;
repu(i, max(n, m), n * m + )
ans += (dp[n][m][i] - dp[n][m][i - ]) * 1.0 * i;
printf("%.12lf\n", ans);
//double f = ans * 3.0; }
return ;
}
ZOJ 3822(求期望)的更多相关文章
- ZOJ 3822 Domination 期望dp
Domination Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem ...
- zoj 3822 Domination(dp)
题目链接:zoj 3822 Domination 题目大意:给定一个N∗M的棋盘,每次任选一个位置放置一枚棋子,直到每行每列上都至少有一枚棋子,问放置棋子个数的期望. 解题思路:大白书上概率那一张有一 ...
- HDU4870_Rating_双号从零单排_高斯消元求期望
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4870 原题: Rating Time Limit: 10000/5000 MS (Java/Other ...
- sgu 495. Kids and Prizes (简单概率dp 正推求期望)
题目链接 495. Kids and Prizes Time limit per test: 0.25 second(s)Memory limit: 262144 kilobytes input: s ...
- ZOJ 3822 Domination
题意: 一个棋盘假设每行每列都有棋子那么这个棋盘达到目标状态 如今随机放棋子 问达到目标状态的期望步数 思路: 用概率来做 计算第k步达到目标状态的概率 进而求期望 概率计算方法就是dp ...
- HDU3853-LOOPS(概率DP求期望)
LOOPS Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others) Total Su ...
- HDU 5159 Card (概率求期望)
B - Card Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Sta ...
- Poj 2096 (dp求期望 入门)
/ dp求期望的题. 题意:一个软件有s个子系统,会产生n种bug. 某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中. 求找到所有的n种bug,且每个子系统都找到bug,这样所要 ...
- poj 2096 Collecting Bugs 【概率DP】【逆向递推求期望】
Collecting Bugs Time Limit: 10000MS Memory Limit: 64000K Total Submissions: 3523 Accepted: 1740 ...
随机推荐
- 08.安装Oracle 10g和SQLServer2008(仅作学习使用VirtualBox虚拟机来安装节省电脑资源)
1.虚拟机和宿主机共享文件夹. 2.右ctrl+F切换VirtualBox全屏 3.安装Oracle 10g 4.输入密码:root------------>下一步 5.勾选网络配置" ...
- [C和指针]第五部分
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- [Effective Java]第三章 对所有对象都通用的方法
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- CUBRID学习笔记 43 insert into
cubrid的中sql查询语法insert into ------ 官方文档是英文的,看不明白可以参看ocracle的同类函数说明.很多都是一样的. INSERT INTO a_tbl1(id) VA ...
- hibernate缓存说明
hibernate缓存说明: 1.一级缓存(session级别缓存) 一级缓存,不是用来提升性能,是用来处理事务的 2.二级缓存(sessionFactory级别缓存): 二级缓存,对 ...
- Android学习参考2
一名自学成才的Android开发者怒答! 1. Google做开发前完全是小白,真心不知道有Google这东西,只晓得百 度,遇到问题直接百度,不是黑百度,百度在娱乐八卦方面确实靠谱,但是技术方面查出 ...
- javascript学习-原生javascript的小特效(原生javascript实现链式运动)
以下代码就不详细解析了,在我之前的多个运动效果中已经解析好多次了,重复的地方这里就不说明了,有兴趣的童鞋可以去看看之前的文章<原生javascript的小特效> <!DOCTYPE ...
- server-pc--------------->lspci,lsusb,meminfo等配置信息
安装yum install pciutils usbutils [root@server09 ~]# [root@server09 ~]# lspci00:00.0 Host bridge: Inte ...
- UML建模
1.包含<<include>> 包含是指当多个用例中存在相同的事件流时,可以把这些公共事件流抽象成公共用例,这个公共用例称之为抽象用例(跟类的概念有点相像,类是多个对象的抽象定 ...
- 转 git使用命令, 特别:git checkout -b a 与 git branch a区别
创建分支: $ git branch mybranch 切换分支: $ git checkout mybranch 创建并切换分支: $ git checkout -b mybranch 更新mast ...