读完题眼前一亮,这不就是24点游戏嘛,小时候和我弟玩过。吐槽一下中兴这个网页编辑器怎么就没法输出看结果呢?我人麻了,编辑器只能给我反馈一个“未通过”,我想输出一下中间结果看一下也不行!?看了半个多小时才发现除法可能会除以0(某两个相等的数相减,然后作为被除数这种情况)。。。。 还是太菜了,除以0都能写得出来。。。
题意给定4个数,是否能用算术运算(±*/和括号)得到24?
分析首先想到的是搜索,前半个小时一直在尝试深度优先搜索去尝试所有情况,但是代码越写越臭,直奔上百行去了,而且也A不掉。然后就仔细想了想以前玩24点游戏,我是怎么快速判断当前4张牌能够凑出24的?应该是先试探2张牌能凑出什么,然后往多了考虑3张牌、4张牌能凑出什么。
于是得出了最终的解决方案,有点动态规划的思想:
定义一个二维数组 m a r k [ i ] [ j ] mark[i][j] mark[i][j]表示 i i i这个状态能否凑出 j j j这个数字。由于数组很大,不妨把第二维换成 m a p map map,反正只是用来标记。其中 i i i是二进制位压缩的牌集合,例如 i = ( 10 ) 10 = ( 1010 ) 2 i=(10)_{10}=(1010)_2 i=(10)10=(1010)2表示取第1和第3张牌。然后就是1张牌、2张牌、3张牌、4张牌依次考虑能凑出来多少。
例如考虑3张牌能凑出来啥的时候,一定是由2张牌和1张牌计算而来的,而4张牌可能是3+1张牌或2+2张牌。
代码#includeusing namespace std; unordered_map mark[16]; void merge(int status1, int status2){ int status = (status1 | status2); for (auto &x : mark[status1]){ for (auto &y : mark[status2]){ mark[status][x.first + y.first] = true; mark[status][abs(x.first - y.first)] = true; mark[status][x.first * y.first] = true; if (y.first > 0 && x.first % y.first == 0) mark[status][x.first / y.first] = true; if (x.first > 0 && y.first % x.first == 0) mark[status][y.first / x.first] = true; } } } bool damage(vector &power){ for (int i = 0; i < 16; i++) mark[i].clear(); // 1 nums for (int i = 0; i < 4; i++) mark[1 << i][power[i]] = true; // 2 nums for (int i = 0; i < 4; i++) for (int j = i + 1; j < 4; j++) merge(1 << i, 1 << j); // 3 nums for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) if (i != j && j != k && k != i) merge((1 << i) | (1 << j), 1 << k); // 4 nums for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) for (int t = 0; t < 4; t++) if (i != j && i != k && i != t && j != k && j != t && k != t) { merge((1 << i) | (1 << j), (1 << k) | (1 << t)); merge((1 << i) | (1 << j) | (1 << k), 1 << t); } return mark[15].count(24) > 0; } // 本地测试: int main() { vector power({1, 1, 2, 7}); cout << damage(power) << endl; }



