(ΦωΦ)<これの答えですよー。目次はここ。
---
問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ループの人はあんまりいませんでした。
(ΦωΦ)<おしまい