题目:uva10651 - Pebble Solitaire(记忆化搜索)
题目大意:12个坑,每个坑里面可以放卵石,也可以不放。然后如果出现00- 或是 -00这样的情况,就可以变成--0和0--。给定初始的状态问最总剩余的卵石个数。
解题思路:这里只有12的位置,并且每个位置只有两种可能,所以可以用二进制数来表示所有的状态。判断卵石的情况每次都是3个3个判断,发现能够转换,就变换成另一个状态直到不能转换为止。因为每个状态最后剩下的卵石是确定的。所以可以用记忆化搜索,之前查找过的状态要将值记录下来,这样下次查找的时候就不用在做一次。这样之前的dp数组就要有一个初始值代表还没有访问过,并且因为这里是要取最小值,所以这里的初始值可以放13.
二进制操作 :
n & (1<<i) 代表取出第i位的值, n | (1<<i) 把第i位变成1, n & (~(1 <<i)) 把第i位变成0。
代码:
#include <cstdio>
#include <cstring>
const int N = 12;
const int maxn = 1 << N;
int dp[maxn];
void init () {
for (int i = 0; i < maxn; i++)
dp[i] = N + 1;
}
int Min (const int a, const int b) { return a < b ? a: b; }
int d (int n) {
if (dp[n] != N + 1)
return dp[n];
int t;
for (int i = 0; i < N - 2; i++) {
t = n;
if ((n & (1 << i)) && (n & (1 << (i + 1))) && ! (n & (1 << (i + 2)))) {
t &= ~(1 << i);
t &= ~(1 << (i + 1));
t |= 1 << (i + 2);
dp[n] = Min (dp[n] , dp[t] = Min (dp[t], d(t)));
} else if (!(n & (1 << i)) && (n & (1 << (i + 1))) && (n & (1 << (i + 2)))) {
t |= 1 << i;
t &= ~(1 << (i + 1));
t &= ~(1 << (i + 2));
dp[n] = Min (dp[n], dp[t] = Min (dp[t], d(t)));
}
}
int cnt = 0;
for (int i = 0; i < N; i++)
if (n & (1 << i))
cnt++;
return dp[n] = Min(dp[n], cnt);
}
int main () {
int t;
int n;
char ch;
scanf ("%d%*c", &t);
init ();
while (t--) {
n = 0;
for (int i = 0; i < N; i++) {
scanf ("%c", &ch);
if (ch == 'o')
n = n | (1 << i);
}
getchar();
printf ("%d\n", d(n));
}
return 0;
}