对帽子状压,0表示没选过,1表示选过但是没有硬币,2表示选过且存在硬币。
可以先dp出每一种情况是否合法,然后dp
显然只要DP出最多能得到几个硬币就好了(magician肯定会从小到大给你硬币)
对于状态S,枚举选择哪个帽子,magician会在“在这个帽子里放硬币”和“在这个帽子里不放硬币”选择较小的。
记忆化搜索一下
// BEGIN CUT HERE
// END CUT HERE
#line 5 "MagicalHats.cpp"
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
int n,m,c,nh;
int f[1594326],g[1594326];
int pw[15];
vector<pair<int,int> > h,cur;
inline int getw(int S,int p){
return S/pw[p]%3;
}
inline int setw(int S,int p,int x){
S-=(S/pw[p]%3)*pw[p];
return S+x*pw[p];
}
int dfs(int S){
if(~g[S]) return g[S];
int r=c;
for(int i=0;i<nh;i++) if(getw(S,i)==2) r--;
if(r==0){
int h=0,r=0;
for(int i=0;i<nh;i++)
if(getw(S,i)!=2) h^=1<<(::h[i].fi),r^=1<<(::h[i].se);
return g[S]=(!h && !r);
}
g[S]=0;
for(int i=0;i<nh;i++)
if(!getw(S,i)) g[S]|=dfs(setw(S,i,2));
return g[S];
}
int trans[1594326],num[1594326],k;
int dp(int S){
int r=c,gs=0;
for(int i=0;i<nh;i++){
if(getw(S,i)==2) r--;
if(getw(S,i)) gs++;
}
if(gs==k) return 0;
if(~f[S]) return f[S];
int &ret=f[S];
for(int i=0;i<nh;i++)
if(!getw(S,i)){
int a=setw(S,i,1),b=setw(S,i,2),cur=1<<30;
if(!g[a] && !g[b]) continue;
if(g[a]) cur=min(cur,dp(a));
if(g[b]) cur=min(cur,dp(b)+1);
ret=max(ret,cur);
}
return ret;
}
class MagicalHats
{
public:
int findMaximumReward(vector <string> board, vector <int> coins, int numGuesses){
n=board.size(); m=board[0].size(); c=coins.size(); h.clear(); k=numGuesses;
memset(f,-1,sizeof(f)); memset(g,-1,sizeof(g));
pw[0]=1; for(int i=1;i<=13;i++) pw[i]=pw[i-1]*3;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(board[i][j]=='H') h.pb(mp(i,j));
nh=h.size();
for(int i=0;i<pw[nh];i++) dfs(i);
dp(0);
if(f[0]<0) return -1;
sort(coins.begin(),coins.end());
int ret=0;
for(int i=0;i<f[0];i++) ret+=coins[i];
return ret;
}
};