Problem Statement

     You might have played the game called Memoria. In this game, there is a board consisting of N rows containing M cells each. Each of the cells has a symbol on its back. Each symbol occurs on exactly two cells on the board.

A move means turning a pair of cells one by one to see the symbols behind them. When the symbols differ, both of the cells are turned on their faces, thus hiding the symbols again. The player should remember the symbols. If the symbols on the backs of the turned cells coincide, the cells stay that way, i.e., don't turn back again. As soon as after some move all the cells on the board are turned (such that all the symbols are simultaneously visible), the game ends.

Manao has a perfect memory, so when he sees the symbol behind some cell, he remembers it forever. Manao is trying to finish the game in the least expected number of moves. Find the expected number of moves he will need to accomplish this.

Definition

    
Class: PerfectMemory
Method: getExpectation
Parameters: int, int
Returns: double
Method signature: double getExpectation(int N, int M)
(be sure your method is public)

Limits

    
Time limit (s): 2.000
Memory limit (MB): 64

Notes

- The board Manao plays on is generated as follows. The same set of (N * M) / 2 symbols is used for each generation. The board contents are chosen uniformly among all valid N x M boards.
- The returned value must have an absolute or relative error less than 1e-9.

Constraints

- N will be between 1 and 50, inclusive.
- M will be between 1 and 50, inclusive.
- N * M will be even.

Examples

0)  
    
1
2
Returns: 1.0
There are only two cells on the board, so the game always ends in one move.
1)  
    
2
2
Returns: 2.6666666666666665
There are four cells. The game may flow in two possible scenarios:

1) In the first move, Manao turns two cells with equal symbols. The game ends in two moves then and the probability of such a first move is 1/3.

2) In the first move, Manao turns two cells with different symbols. Then he finishes the game in three moves and the probability of such a first move is 2/3.

The overall expected number of moves is 1/3 * 2 + 2/3 * 3 = 8/3.

2)  
    
2
3
Returns: 4.333333333333334
 
3)  
    
4
4
Returns: 12.392984792984793
 

题意:你有n*m张卡片,总共n*m/2种,每种有两张。每次操作时你可以翻开两张,若一样,则它们不再翻回去;否则,这两张卡面会向你展示后再翻回去(不改变位置),假设你记忆力很好,能够记住牌的种类。求出至少进行多少次操作,可以使所有牌都同时正面朝上。注意,一次操作翻牌是有先后的,即你可以先翻一张牌,看过其种类后,再决定翻第二张牌。

题解:

假设翻到一样的牌,它们就会被消掉。dp[i][j]表示场上还有i+j张牌未被消掉,已经翻开过其中i张牌(即知道其种类),剩下的j张牌还未被翻开过。

每次操作一定会先翻一张未被翻过的牌,若其与i张牌中的一张对应,则第二张牌一定翻这张,把它们消掉。若是一张新的牌,则第二张牌一定也翻未被翻过的牌。

计算每种情况出现的概率与期望,以j为阶段、i为状态,进行动态规划。

代码:

 double dp[][];
class PerfectMemory
{
public:
double getExpectation(int N, int M)
{
//$CARETPOSITION$
int n=N*M; dp[][]=;
for(int j=;j<=n;j++)
for(int i=;i<=n;i++)
{
if((i==)and(j==))continue; dp[i][j]=;
if(i>j)continue; if(i+j>n)continue; if((j-i)%==)continue;
dp[i][j]=; double p,p2,a1;
p=i; p=p/j; p2=-p;
if((j>)and(i>))
{
dp[i][j]=dp[i][j]+p*(+dp[i-][j-]);
}
double b,c,d;
if(j>)
{
b=; b=b/(j-); c=j--i; c=c/(j-); d=-b-c;
a1=b*(+dp[i][j-])+c*(+dp[i+][j-])+d*(+dp[i][j-]);
dp[i][j]=dp[i][j]+p2*a1;
}
}
return dp[][n]; }
};

TopCoder[SRM513 DIV 1]:PerfectMemory(500)的更多相关文章

  1. TopCoder[SRM513 DIV 1]:Reflections(1000)

    Problem Statement      Manao is playing a new game called Reflections. The goal of the game is trans ...

  2. Topcoder SRM584 DIV 2 500

    #include <set> #include <iostream> #include <string> #include <vector> using ...

  3. topcoder srm 628 div2 250 500

    做了一道题,对了,但是还是掉分了. 第二道题也做了,但是没有交上,不知道对错. 后来交上以后发现少判断了一个条件,改过之后就对了. 第一道题爆搜的,有点麻烦了,其实几行代码就行. 250贴代码: #i ...

  4. SRM 719 Div 1 250 500

    250: 题目大意: 在一个N行无限大的网格图里,每经过一个格子都要付出一定的代价.同一行的每个格子代价相同. 给出起点和终点,求从起点到终点的付出的最少代价. 思路: 最优方案肯定是从起点沿竖直方向 ...

  5. Topcoder SRM583 DIV 2 250

    #include <string> #include <iostream> using namespace std; class SwappingDigits { public ...

  6. 【补解体报告】topcoder 634 DIV 2

    A:应该是道语文题,注意边界就好: B:开始考虑的太复杂,没能够完全提取题目的思维. 但还是A了!我愚蠢的做法:二分答案加暴力枚举, 枚举的时候是完全模拟的,比如每次取得时候都是从大到小的去取,最后统 ...

  7. Topcoder Srm627 DIV 2

    A,B:很水,注意边界,话说HACK都是这些原因. C: R[I][J]:表示反转I-J能改变冒泡排序的次数: DP方程:dp[i][k]=max(dp[j][k],dp[j][k-1]+dp[j][ ...

  8. Topcoder SRM548 Div 1

    1. KingdomAndTrees 给出n个数a[1..n],求一个数组b[1..n]满足b严格递增,且b[1]>=1. 定义代价为W = max{abs(a[i]-b[i])},求代价最小值 ...

  9. TopCoder SRM 675 Div1 Problem 500 LimitedMemorySeries1(分块)

    题意  给定一个长度不超过$5*10^{6}$的数列和不超过$100$个询问,每次询问这个数列第$k$小的数,返回所有询问的和 内存限制很小,小到不能存下这个数列.(数列以种子的形式给出) 时限$10 ...

随机推荐

  1. keepAlived主备及双主

    nginx用默认配置即可 1.主备配置 1.主keepAlived配置 vrrp_instance VI_1 { state MASTER #主备区分 interface eth0 virtual_r ...

  2. Google 公司的代码规范

    如题: C++ , Objective-C, Java, Python, R, Shell, HTML/CSS, JavaScript, AngularJS, Common Lisp ,Vimscri ...

  3. windows 远程登录

    在我的电脑  属性当中开启远程登录功能 然后制作账号,这里对于账号的命名是有要求的,具体网上查找说是要用户名和全名一样,我没有做测试,不过新创建了一个用户用来登录,总是告知我密码错误,导致登录失败,所 ...

  4. Jenkins添加Windows自动化构建方案

    一.为Jenkins添加Windows节点 这里需要填写远程工作目录,启动方法一项一定要选择"Launch agent via Java Web Start"一项,其它的保持默认. ...

  5. 使用node搭建简单的服务

    //创建依赖模块var http = require('http');var url = require('url');var fs = require('fs');var server = http ...

  6. MySQL 刷题知识点整理

    1. left join on 与 right join on, inner join on 的区别: left join on 把左表中的行全部展示,而将寻找右表中符合的行展示: right joi ...

  7. NX二次开发-UFUN计时函数UF_begin_timer

    NX9+VS2012 #include <uf.h> #include <uf_modl.h> UF_initialize(); //计时开始 UF_timer_t Timer ...

  8. 如何通过编程发现Java死锁

    本文由 ImportNew - rookie_sam 翻译自 Dzone.欢迎加入翻译小组.转载请见文末要求. 死锁是指,两个或多个动作一直在等待其他动作完成而使得所有动作都始终处在阻塞的状态.想要在 ...

  9. Mysql命令增加、修改、删除表字段

    alter add 命令用来增加表的字段: alter add命令格式:alter table 表名 add字段 类型 其他:如下所示: ) comment '单位' alter drop 命令删除表 ...

  10. licecap图片区域问题

    之前一直好用的licecap最近突然没法用了,结果发现是屏幕分辨率的文本大小的问题,因为选了特大的.发现制作成的gif图片的区域有问题.后来改回中等的,就可以了.