2139 - Memory Match

問題

2枚ずつのM種類のカードN(=2M)枚で1人神経衰弱をする。
今までに開けたカード全てを記憶出来るとき、ミスマッチする回数の期待値を求めよ。

制約

2<=N<=1000

解法

カードを1列に並べたものをイメージして、左から順に開けていく。
今開けようとしているカードの位置、1回開けたがまだマッチしていないカードの枚数を引数としてメモ化再帰

ソース
double memo[1000][1000];
int n;
double solve(int now, int rest) { // rest : 開けたけど残っているもの
  if (now >= n) return 0;
  if (memo[now][rest] >= 0) return memo[now][rest];
  int num = rest+1;
  double res = 0;
  double p = (double)rest/(n-now);
  if (rest) {
    res += solve(now+1, rest-1) * p; // 既に開けた奴とマッチ
  }
  // 1枚目が初めて
  p = 1-p;
  if (rest != n-now) {
    // 2枚目が既に開けたやつ
    double q = (double)rest/(n-now-1);
    if (rest) {
      res += (1 + solve(now+2, rest)) * p * q;
    }
    // 2枚目も初めて
    q = double(n-now-1-rest-1)/(n-now-1);
    if (n-now-1-rest-1) {
      res += (1 + solve(now+2, rest+2)) * p * q;
    }
    // 2枚目が同じ
    q = 1.0/(n-now-1);
    res += solve(now+2, rest) * p * q;
  }
  return memo[now][rest] = res;
}

int main() {
  while(cin>>n,n) {
    REP(i,n)REP(j,n) memo[i][j] = -1;
    printf("%.10f\n", solve(0,0));
  }
}