1655. 分配重复整数(状压dp,枚举子集的子集)
给你一个长度为 n
的整数数组 nums
,这个数组中至多有 50
个不同的值。同时你有 m
个顾客的订单 quantity
,其中,整数 quantity[i]
是第 i
位顾客订单的数目。请你判断是否能将 nums
中的整数分配给这些顾客,且满足:
- 第
i
位顾客 恰好 有quantity[i]
个整数。 - 第
i
位顾客拿到的整数都是 相同的 。 - 每位顾客都满足上述两个要求。
如果你可以分配 nums
中的整数满足上面的要求,那么请返回 true
,否则返回 false
。
示例 1:
输入:nums = [1,2,3,4], quantity = [2] 输出:false 解释:第 0 位顾客没办法得到两个相同的整数。
示例 2:
输入:nums = [1,2,3,3], quantity = [2] 输出:true 解释:第 0 位顾客得到 [3,3] 。整数 [1,2] 都没有被使用。
示例 3:
输入:nums = [1,1,2,2], quantity = [2,2] 输出:true 解释:第 0 位顾客得到 [1,1] ,第 1 位顾客得到 [2,2] 。
示例 4:
输入:nums = [1,1,2,3], quantity = [2,2] 输出:false 解释:尽管第 0 位顾客可以得到 [1,1] ,第 1 位顾客没法得到 2 个一样的整数。
示例 5:
输入:nums = [1,1,1,1,1], quantity = [2,3] 输出:true 解释:第 0 位顾客得到 [1,1] ,第 1 位顾客得到 [1,1,1] 。
提示:
n == nums.length
1 <= n <= 1e5
1 <= nums[i] <= 1000
m == quantity.length
1 <= m <= 10
1 <= quantity[i] <= 1e5
nums
中至多有50
个不同的数字。
这个一看数据范围就知道,应该是一个dfs或者状态压缩dp
首先先把每一个数的出现次数处理出来,f[i][j]代表的是前i个能不能把状态j给表示出来
然后如果能表示出来的话,然后再枚举j这个状态的的的子集,如果i+1这个数字出现次数能表示出来这个子集那么
f[i+1][j|k]=1;
就是这样转移的
然后最后只需要判断一下这个f[n][(1<<m)]
然后这有个小优化如果你枚举子集的子集的话可以从2^(2*n)优化到3^n,这是这个题的主要,要不然你会超时的
class Solution { public: bool canDistribute(vector<int>& nums, vector<int>& quantity) { unordered_map<int,int>hash; for(auto x:nums){ hash[x]++; } vector<int>w(1); for(auto [x,y]: hash) w.push_back(y); int n=hash.size(),m=quantity.size(); vector<int>s(1<<m); for(int i=0;i<(1<<m);i++){ for(int j=0;j<m;j++){ if((i>>j)&1){ s[i]+=quantity[j]; } } } vector<vector<int>> f(n+1,vector<int>(1 << m)); f[0][0]=1; for(int i=0;i<n;i++){ for(int j=0;j<(1<<m);j++){ if(f[i][j]){ f[i+1][j]=1; for(int t=j^((1<<m)-1),k=t;k;k=(k-1)&t){ if(s[k]<=w[i+1]){ f[i+1][j|k]=1; } } } } } return f[n][(1<<m)-1]; } };