Memory Game

Memory Game

The game of Memory is played with NN pairs of cards where each pair has the same picture, i.e. there are NN different pictures, and each of them appear on exactly two cards.

The cards are shuffled and placed face down on a large table. On each turn you flip two cards of your choice face up. If they match you remove them from the game, and if they don’t match, you turn them face down. The goal of the game is to remove all cards from the game.

Your strategy is simple:

  • If you know of two face-down cards which have the same picture, choose both of them.
  • Otherwise,
    • Turn a random card that you have not looked at before face up.
    • If it matches a card you have seen, turn the matching card face up (you have excellent memory).
    • If the first card did not match a card you had seen before, turn another random unknown card face up.

Given this strategy, what is the expected number of turns you have to play in order to finish the game?

Input

Input is a single integer NN indicating the number of pairs of cards.

Output

Output the expected number of turns needed to finish the game. This number must have an absolute or relative error of at most 106

Limits

1≤N≤1000

Sample 1

1
1.000000000

Sample 2

2
2.666666666667

题意

给你 n 对纸牌,每一轮可以翻开两个纸牌,如果相同则可以消除,不同则记住牌的位置和样式,继续游戏。

n对纸牌,需要多少轮才能够结束,求期望。

解法

分类讨论DP

dp[i][j]表示,现有i张牌,已经知道了j张牌的位置,这时候消除完的期望是多少。所以未知牌的个数是i-2*j

  1. 新的一轮中,在未知的牌里选,第一次拿出了已知牌的另一个,第二次选对应的已知牌,概率是 jij ,从dp[i-2][j-1]中,需要1步。
  2. 新的一轮中,在未知的牌里选,第一次拿出了未知的牌,概率是 i2jj ,此时的状态是已知j+1张牌,未知i-j-1张牌:
    1. 第二次,拿出了另一张未知的牌,概率是 i(j+1)2ij1 ,从dp[i][j+2]转移,需要1步;
    2. 第二次,拿出了同一张未知的牌,概率是 1ij1 ,从dp[i-2][j]转移,需要1步;
    3. 第二次,拿出了一张上一轮就已知的牌,概率是 jij1 ,从dp[i-2][j]转移,需要两步(因为这一轮没有消除,需要多一轮以 1 <script type="math/tex" id="MathJax-Element-716">1</script>的概率选出两张出现过的已知牌)。

代码

//      whn6325689
//      Mr.Phoebe
//      http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")


using namespace std;
#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<50
#define speed std::ios::sync_with_stdio(false);

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;

#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))
#define debug(a) cout << #a" = " << (a) << endl;
#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }

#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))

#define MID(x,y) (x+((y-x)>>1))
#define getidx(l,r) (l+r | l!=r)
#define ls getidx(l,mid)
#define rs getidx(mid+1,r)
#define lson l,mid
#define rson mid+1,r

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
template <class T>
inline void write(T n)
{
    if(n < 0)
    {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n)
    {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
//-----------------------------------


double dp[2010][2010];

double dfs(int i, int j)
{

    if(j < 0 || i <= 0 || j*2 > i)  return 0;
    if(dp[i][j]>0.0)   return dp[i][j];
    if(i == 2)  return dp[i][j] = 1.0;

    dp[i][j] = 0;

    if(j*2 < i)
    {
        dp[i][j] += (dfs(i-2,j)+1)*1/(i-j-1);
        dp[i][j] += (dfs(i,j+2)+1)*(i-(j+1)*2)/(i-j-1);
        dp[i][j] += (dfs(i-2,j)+2)*j/(i-j-1);
        dp[i][j] *= (i-2.0*j)/(i-j);
    }
    dp[i][j] += 1.0*j/(i-j)*(dfs(i-2,j-1)+1);
    return dp[i][j];
}

int main()
{
    int n;
    read(n);
    for(int i = 0; i < 2*n+3; i++)
        for(int j = 0; j < 2*n+3; j++)
            dp[i][j] = -1.0;
    printf("%.6f\n", dfs(2*n, 0));

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值