根据题目描述,每次变换都减少了一个石子,所以只要求出初始状态最多可以变换多少次,用初始状态石子数目减去这个变换次数就得到最后剩余最少的石子的数目;
最多有12位,用一个 int 表示状态,状态的转移可以用位运算实现。
1 /* 2 UVA 10651 - Pebble Solitaire 3 */ 4 # include <cstdio> 5 # include <cstring> 6 7 char s[20]; 8 int f[5000]; 9 10 bool move(int &x, int i, char d) 11 { 12 int t = (x>>(i-2))&0x7; 13 if (d) 14 { 15 if (t == 0x6) 16 { 17 x&=~(1<<i); 18 x&=~(1<<(i-1)); 19 x|=1<<(i-2); 20 return true; 21 } 22 return false; 23 } 24 else 25 { 26 if (t == 0x3) 27 { 28 x|=1<<i; 29 x&=~(1<<(i-1)); 30 x&=~(1<<(i-2)); 31 return true; 32 } 33 return false; 34 } 35 } 36 37 int max(int x, int y) 38 { 39 return x>y ? x:y; 40 } 41 42 int dp(int cur) 43 { 44 int &ans = f[cur]; 45 if (ans >= 0) return ans; 46 ans = 0; 47 int nst = cur; 48 for (int i = 11; i > 1; --i) if (move(nst, i, 0)) // oo- 49 { 50 ans = max(dp(nst)+1, ans); 51 nst = cur; 52 } 53 nst = cur; 54 for (int i = 11; i > 1; --i) if (move(nst, i, 1)) // -oo 55 { 56 ans = max(dp(nst)+1, ans); 57 nst = cur; 58 } 59 60 return ans; 61 } 62 63 int trans(char *s) 64 { 65 int ret = 0; 66 for (int i = 0; i < 12; ++i) 67 if (s[i] == 'o') ret |= 1<<i; 68 return ret; 69 } 70 int count(char *s) 71 { 72 int ret = 0; 73 for (int i = 0; i < 12; ++i) 74 if (s[i] == 'o') ++ret; 75 return ret; 76 } 77 78 void solve(void) 79 { 80 memset(f, -1, sizeof(f)); 81 int tmp = trans(s); 82 int ans = count(s) - dp(tmp); 83 printf("%d\n", ans); 84 } 85 86 int main() 87 { 88 int T; 89 scanf("%d", &T); 90 while (T--) 91 { 92 scanf("%s", s); 93 solve(); 94 } 95 96 return 0; 97 }
这算是状态压缩???