题目:有一个类似跳棋的游戏,一共有12个位置'o'代表棋子'-'代表空位,
'oo-'可以转化成'--o','-oo'可以转化成'o--',给你初始状态,问最后,至少剩下几个棋子。
分析:dp,记忆化搜索,位运算。利用搜索在相邻状态间dp即可。
每个状态的最优解为他能转化所有状态中的最优解。
因为,一共有2^12 = 4096个状态,每次找到解即存储,不会重复计算,所以时间方面没问题。
利用一个12位整数表示一个状态,'o'用1表示,'-'用0表示,则’---oo-------‘为24(2进制000000011000)
(这里是从左向右代表低位到高位,倒过来也可以)
通过观察可以发现'oo-'(011)转化成'--o'(100),'-oo'(110)转化成'o--'(001)都是对应为取反;
直接利用7(2进制111)进行异或即可,而对应额可以跳的状态为3(2进制011)与6(2进制110);
说明:详细参考代码。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdio>
#include <cmath>
using namespace std;
char buf[13];
int F[4100];
int dfs(int s)
{
if (F[s] < 13) return F[s];
int Min = 12;
for (int i = 0 ; i < 10 ; ++ i)
if (((s>>i)&7) == 3 || ((s>>i)&7) == 6)
Min = min(Min, dfs(s^(7<<i)));
if (Min == 12) {
for (int i = 0 ; i < 12 ; ++ i)
Min -= !(s&(1<<i));
}
return F[s] = Min;
}
int main()
{
for (int i = 0 ; i < 4100 ; ++ i)
F[i] = 13;
int n,v;
while (~scanf("%d",&n))
for (int i = 1 ; i <= n ; ++ i) {
scanf("%s",buf);
v = 0;
for (int j = 0 ; j < 12 ; ++ j) {
v <<= 1;
if (buf[j] == 'o') v += 1;
}
printf("%d\n",dfs(v));
}
return 0;
}