1.题目
2.求解
这是一道隐藏的状态压缩题,我看到第一眼,根本没想到是状压dp。常态的状压dp题是使用二进制保存数据的当前状态,而这里面的状态一般只有取(1)和不取(0),这也是我们最常用的。
但是在本题中,为三进制状压dp,三进制保存篮子里已存放了0, 1, 2个整数,不像二进制可以使用GCC中的 __builtin_popcount() 函数可以直接获得当前存放到第几个整数。三进制需要我们手动遍历求余取和。除此之外,在状态转移方程的位置二进制可以直接使用位运算 1<<n,但是三进制需要手动更新数据。
所幸的是,除了三进制的点,其他的都是套用模板即可。但是根据这道题下次是否可以使用其他进制呢?只要n够小,只要内存够,应该就能用来求解对应的题目。
学到了新的知识,第一次碰到这种非常规进制的状压题目,很有趣!
3.代码
int nums[20];
const int maxn = 19690;
class Solution {
public:
int maximumANDSum(vector<int>& nums, int numSlots) {
int nummax = pow(3, numSlots);
int dp[nummax];
memset(dp, -1, sizeof(dp));
dp[0] = 0;
int ans = 0;
int i, j, k;
int n = nums.size();
for (i = 0; i < nummax; i++) {
if (dp[i] == -1) continue;
int cnt = 0;
int sta = i;
while (sta > 0) {
cnt += (sta % 3);
sta /= 3;
}
if (cnt == n) {
ans = max(ans, dp[i]);
continue;
}
int cur;
for (j = i, cur = 1, k = 1; k <= numSlots; j /= 3, cur *= 3, k++) {
if (j % 3 == 2) continue;
dp[i + cur] = max(dp[i + cur], dp[i] + (nums[cnt] & k));
}
}
return ans;
}
};