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 10−6
Limits
1≤N≤1000
Sample 1
1
1.000000000
Sample 2
2
2.666666666667
题意
给你 n 对纸牌,每一轮可以翻开两个纸牌,如果相同则可以消除,不同则记住牌的位置和样式,继续游戏。
问
解法
分类讨论DP
dp[i][j]
表示,现有i
张牌,已经知道了j
张牌的位置,这时候消除完的期望是多少。所以未知牌的个数是i-2*j
- 新的一轮中,在未知的牌里选,第一次拿出了已知牌的另一个,第二次选对应的已知牌,概率是
ji−j
,从
dp[i-2][j-1]
中,需要1步。 - 新的一轮中,在未知的牌里选,第一次拿出了未知的牌,概率是
i−2∗jj
,此时的状态是已知
j+1
张牌,未知i-j-1
张牌:
- 第二次,拿出了另一张未知的牌,概率是
i−(j+1)∗2i−j−1
,从
dp[i][j+2]
转移,需要1步; - 第二次,拿出了同一张未知的牌,概率是
1i−j−1
,从
dp[i-2][j]
转移,需要1步; - 第二次,拿出了一张上一轮就已知的牌,概率是
ji−j−1
,从
dp[i-2][j]
转移,需要两步(因为这一轮没有消除,需要多一轮以 1 <script type="math/tex" id="MathJax-Element-716">1</script>的概率选出两张出现过的已知牌)。
- 第二次,拿出了另一张未知的牌,概率是
i−(j+1)∗2i−j−1
,从
代码
// 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;
}