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];
    }
};

 

posted @ 2021-05-19 00:04  lipu123  阅读(86)  评论(0)    收藏  举报