leetcode1681

/*状态压缩 这种集合元素不是特别多(n<16)的集合等分,可以考虑使用基于二进制的集合状态记录
首先预处理所有含有n/k元素的value值 用于最优化(动态规划)的时候使用
然后dp过程其实就是暴搜 针对子集合状态mask 考察他所有的子集合sub 有如下状态转移方程
dp[mask] = min{sub合法 |dp[mask ^ sub] + value[sub]}*/
class Solution {
public:
    int minimumIncompatibility(vector<int>& nums, int k) {
          int n = nums.size();
          vector <int> value(1 << n , -1);
          vector <int> hash(n + 1);

          for(int sub = 0;sub < (1 << n);sub++){
              if(__builtin_popcount(sub) == n / k){//含有n/k元素的子集合的状态
                   for(int j = 0;j < n;j++){//该状态是否合法 [查重]
                        if(sub & (1 << j)){
                             hash[nums[j]]++;
                        }
                   }
                   int flag = 1;
                   for(int j = 1;j < n + 1;j++){
                        if(hash[j] > 1) {
                            flag = 0;
                            break;
                        }
                   }
                   if(flag == 1){
                        int Min = INT_MAX;
                        int Max = INT_MIN;
                        for(int i = 1;i <= n;i++)
                         if(hash[i] > 0){
                              Min = min(Min , i);
                              Max = max(Max , i);
                         }
                         value[sub] = Max - Min;
                   }
                   

                    for(int j = 0;j < n;j++){//该状态是否合法 [查重]
                        if(sub & (1 << j)){
                             hash[nums[j]]--;
                        }
                   }
              }
          }

          vector<int> dp(1 << n , -1);
          dp[0] = 0;
          for(int mask = 0;mask < (1<<n);mask++){
               if(__builtin_popcount(mask) %(n/k) == 0){
                     for(int sub = mask;sub;sub = (sub - 1)&mask){//枚举当前状态的子集合
                         if(value[sub] != -1 && dp[mask ^ sub] != -1){
                             //子集合合法(含有规定元素 即提前预处理过)  剩余集合非空(合法)
                              if(dp[mask] == -1){
                                  dp[mask] = dp[mask ^ sub] + value[sub];
                              }
                              else{
                                   dp[mask] = min(dp[mask] , dp[mask^sub] + value[sub]);
                              }
                         }
                     }
               }
          }
          return dp[(1 << n) - 1];
    }
};

 

posted on 2020-12-07 15:16  在苏州的城边  阅读(109)  评论(0编辑  收藏  举报

导航