Top

(ΦωΦ)<これの答えですよー。目次はここ

---
問3-1
(ΦωΦ)<メモ化再帰
#include <iostream>
#include <algorithm>
using namespace std;

class RowAndCoins { public: string getWinner(string cells); };

int n;
string cells;
vector<vector<int>> dp;

// 猫メダルが今どこに置いてあるという状態をもとに、
// 新しく猫メダルを置いたとき、アリスが勝つかどうかを返す。
bool rec(bool isBob, int mask) {
  if(dp[isBob][mask] != -1) { return dp[isBob][mask]; }
  if(__builtin_popcount(mask) == n-1) {
    for(int i=0; i<n; i++) {
      if(mask>>i & 1) { continue; }
      return dp[isBob][mask] = cells[i] == 'A' + isBob;
    }
  }
  for(int i=0; i<n; i++) {
    if(mask >> i & 1) { continue; }
    int nmask = mask;
    for(int j=i; j<n && !(mask>>j & 1); j++) {
      nmask |= 1<<j;
      if(nmask == (1<<n)-1) { continue; } // (ΦωΦ)<全部のセルに猫メダルを置いてはいけない
      if(!rec(!isBob, nmask)) { return dp[isBob][mask] = true; }
    }
  }
  return dp[isBob][mask] = false;
}

string RowAndCoins::
getWinner(string _cells) {
  cells = _cells;
  n = cells.size();
  dp.assign(2, vector<int>(1<<n, -1));
  return rec(false, 0) ? "Alice" : "Bob";
}
    

(ΦωΦ)<forループ
#include <iostream>
#include <algorithm>
using namespace std;

class RowAndCoins { public: string getWinner(string cells); };

string RowAndCoins::
getWinner(string cells) {
  int n = cells.size();
  vector<vector<bool>> dp(2, vector<bool>(1<<n));
  for(int mask=(1<<n)-1; mask>=0; mask--) {
    if(__builtin_popcount(mask) == n-1) {
      for(int i=0; i<n; i++) {
        if(mask>>i & 1) { continue; }
        dp[cells[i]=='B'][mask] = true;
      }
      continue;
    }
    for(int i=0; i<n; i++) {
      if(mask >> i & 1) { continue; }
      int nmask = mask;
      for(int j=i; j<n && !(mask>>j & 1); j++) {
        nmask |= 1<<j;
        if(nmask == (1<<n)-1) { continue; }
        if(!dp[0][nmask]) { dp[1][mask] = true; }
        if(!dp[1][nmask]) { dp[0][mask] = true; }
      }
    }
  }
  return dp[0][0] ? "Alice" : "Bob";
}
    

(ΦωΦ)<forループ おまけのPetr方式
#include <iostream>
#include <algorithm>
using namespace std;

class RowAndCoins { public: string getWinner(string cells); };

string RowAndCoins::
getWinner(string cells) {
  int n = cells.size();
  vector<vector<bool>> dp(2, vector<bool>(1<<n));
  for(int mask=0; mask<1<<n; mask++) {
    if(__builtin_popcount(mask) == 1) {
      for(int i=0; i<n; i++) {
        if(!(mask>>i & 1)) { continue; }
        dp[cells[i]=='B'][mask] = true;
      }
      continue;
    }
    for(int i=0; i<n; i++) {
      for(int j=1; j<=n-i; j++) {
        int put = ((1<<j) - 1) << i;
        if((mask & put) == put && mask != put) { // putがmaskの真部分集合なら真
          int nmask = mask & ~put;
          if(!dp[0][nmask]) { dp[1][mask] = true; }
          if(!dp[1][nmask]) { dp[0][mask] = true; }
        }
      }
    }
  }
  return dp[0][(1<<n)-1] ? "Alice" : "Bob";
}
    

探索をやっているほとんどの人はメモ化再帰で解いてて、forループの人はあんまりいませんでした。

(ΦωΦ)<おしまい