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 <= NM <= 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(求期望)的更多相关文章

  1. ZOJ 3822 Domination 期望dp

    Domination Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem ...

  2. zoj 3822 Domination(dp)

    题目链接:zoj 3822 Domination 题目大意:给定一个N∗M的棋盘,每次任选一个位置放置一枚棋子,直到每行每列上都至少有一枚棋子,问放置棋子个数的期望. 解题思路:大白书上概率那一张有一 ...

  3. HDU4870_Rating_双号从零单排_高斯消元求期望

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4870 原题: Rating Time Limit: 10000/5000 MS (Java/Other ...

  4. sgu 495. Kids and Prizes (简单概率dp 正推求期望)

    题目链接 495. Kids and Prizes Time limit per test: 0.25 second(s)Memory limit: 262144 kilobytes input: s ...

  5. ZOJ 3822 Domination

    题意: 一个棋盘假设每行每列都有棋子那么这个棋盘达到目标状态  如今随机放棋子  问达到目标状态的期望步数 思路: 用概率来做  计算第k步达到目标状态的概率  进而求期望  概率计算方法就是dp  ...

  6. HDU3853-LOOPS(概率DP求期望)

    LOOPS Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others) Total Su ...

  7. HDU 5159 Card (概率求期望)

    B - Card Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Sta ...

  8. Poj 2096 (dp求期望 入门)

    / dp求期望的题. 题意:一个软件有s个子系统,会产生n种bug. 某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中. 求找到所有的n种bug,且每个子系统都找到bug,这样所要 ...

  9. poj 2096 Collecting Bugs 【概率DP】【逆向递推求期望】

    Collecting Bugs Time Limit: 10000MS   Memory Limit: 64000K Total Submissions: 3523   Accepted: 1740 ...

随机推荐

  1. CUBRID学习笔记 28 执行sql脚本文件

    一下命令在csql下执行. insert_commands.sql为sql脚本文件 ;CL ;READ insert_commands.sql ;RU 第一行的cl 清空命令缓存,等同clear第二行 ...

  2. FLASH CC 2015 CANVAS 中 createjs 移除绑定事件

    myBtn.addEventListener("click", function(evt) { // do stuff... evt.remove(); // removes th ...

  3. Java中的内省

    为什么要学内省? •开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性.   什么是Ja ...

  4. DBCP、C3P0、Proxool 、 BoneCP开源连接池的比《转》

     简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等待时 ...

  5. Corelocation及地图控件学习笔记

    Corelocation基本使用 在地图章节的学习中,首先要学的便是用户位置定位,因此我们首先要掌握Corelocation的使用.(在IOS8以前可以系统会直接请求授权,现在需要我们自己调用方式通知 ...

  6. poj2451Uyuw's Concert(半平面交)

    链接 逆时针给出线段,如果模板是顺时针的修改下系数的符号进行平面交即可. #include <iostream> #include<cstdio> #include<cs ...

  7. 下载安装APK

    protected void downloadApk() { //apk下载链接地址,放置apk的所在路径 //1,判断sd卡是否可用,是否挂在上 if(Environment.getExternal ...

  8. The new day of my blog

    今天开始了我的博客建造之旅,作为一个ACMer(虽说是弱校的),我也想象其他人一样把自己的题解和心得记录下来,一来可以和大家分享一下,二来也可以留给将来的自己作回顾,希望众大神能够给以指导指导,让我这 ...

  9. spring.hibernate设置参数的位置问题

    1.spring的注解设置在set方法上 2.hibernate的注解设置在get方法上

  10. 【linux命令】:查看当前登录用户的信息,本文介绍3种方法

    作为系统管理员,你可能经常会(在某个时候)需要查看系统中有哪些用户正在活动.有些时候,你甚至需要知道他(她)们正在做什么.本文为我们总结了4种查看系统用户信息(通过编号(ID))的方法. 1. 使用w ...