250824 thinking 状压dp
状压dp使用二进制数来表示状态,将当前已选元素的集合表示为一个二进制数。
适用于需要枚举每一种排列进行判断、且最大的$n$有$10<n<20$的题目。
状压dp能使得时间复杂度从暴力搜索的$O(n!)$降到$O(n*2^n)$(相邻无关)或者$O(n^2 * 2^n)$(相邻相关)。
若当前表示已选元素的集合的二进制掩码为mask,则;
mask &(1<<i): 表示第i个元素是否被选择mask|(1<<i): 表示将第i个元素加入集合popcount(mask): 表示集合中元素的个数
1. 相邻无关
当前位置的选择不依赖于前一个位置的选择,只依赖于当前已选元素的集合。
$dp[mask]$表示状态为mask的情况(即已经选择的集合的二进制掩码为mask)下的最优解。
1.1 例题
假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组 perm(下标从 1 开始),只要满足下述条件 之一 ,该数组就是一个 优美的排列 :
- perm[i] 能够被 i 整除
- i 能够被 perm[i] 整除
- 1 <= n <= 15
给你一个整数 n ,返回可以构造的 优美排列 的 数量 。
1 | int countArrangement(int n) { |
2. 相邻相关
当前位置的选择不仅依赖于当前已选元素的集合,还依赖于前一个位置的选择。
$dp[mask][i]$表示状态为mask、前一个位置的选择为i的情况下的最优解。
2.1 例题
给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数。如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列:
- 对于 0 <= i < n - 1 的下标 i ,要么 nums[i] % nums[i+1] == 0 ,要么 nums[i+1] % nums[i] == 0 。
- 2 <= nums.length <= 14
- 1 <= nums[i] <= 1e9
请你返回特别排列的总数目。由于答案可能很大,请将它对 $10^9 + 7$ 取余后返回。
1 | int specialPerm(vector<int>& nums) { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Elian's blog page!