📌  相关文章
📜  最小化由唯一元素组成的K个等长子集的不兼容性之和

📅  最后修改于: 2021-04-17 18:40:44             🧑  作者: Mango

给定由N个整数和整数K组成的数组arr [] 任务是找到具有唯一元素的相等大小的K个子集的不兼容性的最小总和。

例子:

天真的方法:最简单的方法是递归遍历给定的数组,并且在每次递归中遍历使用位掩码选择数组N / K元素的所有可能方式,并计算该子集的不兼容性,然后返回所有子集中的最小值。

时间复杂度: O(N * 2 3 * N )
辅助空间: O(N)

高效方法:可以使用动态编程来优化上述方法。可以根据以下观察结果解决给定的问题:

  • 可以观察到,需要使用位屏蔽说DP(mask,i)的2状态动态编程来解决以下问题: i代表数组的当前位置,而mask的每个二进制位代表元素是否已被选择。
  • 过渡状态将包括通过选择大小为N / K的子集来计算不兼容性。
    • 假设XY是当前设置的最小值和最大值,而newmask是另一个变量,其初始值是mask
    • 现在,标记所有已选定的N / K个元素中为newmask然后DP(掩模,i)(Y只计算一次发生– X +分钟(DP(为newmask,I + 1),DP(掩模,i)的))

请按照以下步骤解决问题:

  • 初始化一个2D数组,例如dp [] []
  • 定义一个递归函数,例如dfs(mask,i) ,以计算结果:
    • 基本情况:如果i> K ,则返回0
    • 检查dp [mask] [i]!= -1 ,然后返回dp [mask] [i],因为已经计算出当前状态。
    • 使用位掩码从数组中选择N / K个元素,如果可以选择仅出现一次且不属于其他子集的i个子集元素,则将当前dp状态更新为:
  • 返回dp [mask] [i]的值作为当前递归调用中的结果。
  • 调用递归函数dfs(2 N -1,0)并打印其返回的值。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
int k;
int n;
int goal;
vector> dp;
vector bits;
 
// Recursive function to find
// the minimum required value
int dfs(vector A, int state,int index)
{
   
    // Base Case
    if (index >= k)
    {
        return 0;
    }
 
    // Stores the minimum value
    // of the current state
    int res = 1000;
 
    // If dp[state][index] is
    // already calculated
    if (dp[state][index] != -1) {
 
        // return dp[state][index]
        return dp[state][index];
    }
 
    // Traverse over all the bits
    for (int bit : bits) {
 
        // If count of set bit is N/K
        if (__builtin_popcount(bit)
            == goal) {
 
            // Store the new state after
            // choosing N/K elements
            int newstate = state;
 
            // Stores the minimum and
            // maximum of current subset
            int mn = 100, mx = -1;
 
            // Stores if the elements
            // have been already
            // selsected or not
            vector visit(n+1,false);
 
            // Stores if it is possible
            // to select N/K elements
            bool good = true;
 
            // Traverse over the array
            for (int j = 0; j < n; j++) {
 
                // If not chosen already
                // for another subset
                if ((bit & (1 << j)) != 0) {
 
                    // If already chosen
                    // for another subset
                    // or current subset
                    if (visit[A[j]] == true
                        || (state & (1 << j)) == 0) {
 
                        // Mark the good false
                        good = false;
                        break;
                    }
 
                    // Mark the current
                    // number visited
                    visit[A[j]] = true;
 
                    // Mark the current
                    // position in mask
                    // newstate
                    newstate = newstate
                               ^ (1 << j);
 
                    // Update the maximum
                    // and minimum
                    mx = max(mx,
                                  A[j]);
                    mn = min(mn,
                                  A[j]);
                }
            }
 
            // If good is true then
            // Update the res
            if (good) {
                res = min(
                    res, mx - mn
                             + dfs(A, newstate,
                                   index + 1));
            }
        }
    }
 
    // Update the current sp state
    dp[state][index] = res;
 
    // Return the res
    return res;
}
 
// Function to find the minimum
// incomatibility sum
int minimumIncompatibility(vector A, int K)
{
    n = A.size();
    k = K;
    goal = n / k;
 
    // Stores the count of element
    map mp;
 
    // Traverse the array
    for (int i : A) {
 
        // If number i not occurs
        // in Map
        if (mp.find(i)!=mp.end()){
            // Put the element
            // in the Map
            mp[i] = 0;
          }
 
        // Increment the count of
        // i in the Hash Map
        mp[i]++;
 
        // If count of i in Map is
        // greater than K then
        // return -1
        if (mp[i] > k)
            return -1;
    }
 
    // Stores all total state
    int state = (1 << n) - 1;
 
    // Travere over all the state
    for (int i = 0; i <= state; i++) {
 
        // If number of set bit
        // is equal to N/K
        if (__builtin_popcount(i) == goal)
            bits.push_back(i);
    }
 
    // Stores the minimum value
    // at a state
    dp.resize(1<(k,-1));
 
    // Intiallize the dp state
    // with -1
    // for (int i = 0;
    //      i < dp.ize(); i++) {
    //     Arrays.fill(dp[i], -1);
    // }
 
    // Call the recursive function
    return dfs(A, state, 0);
}
 
// Driver code
int main()
{
 
    vector arr = { 1, 2, 1, 4 };
    int K = 2;
 
    // Function Call
    cout<<(minimumIncompatibility(arr, K));
}
 
// This code is contributed by mohit kumar 29.


Java
// Java program for the above approach
import java.io.*;
import java.util.*;
 
class Solution {
    int k;
    int n;
    int goal;
    int dp[][];
    List bits = new ArrayList<>();
 
    // Function to find the minimum
    // incomatibility sum
    public int minimumIncompatibility(
        int[] A, int k)
    {
        this.n = A.length;
        this.k = k;
        goal = n / k;
 
        // Stores the count of element
        Map map
            = new HashMap<>();
 
        // Traverse the array
        for (int i : A) {
 
            // If number i not occurs
            // in Map
            if (!map.containsKey(i))
 
                // Put the element
                // in the Map
                map.put(i, 0);
 
            // Increment the count of
            // i in the Hash Map
            map.put(i, map.get(i) + 1);
 
            // If count of i in Map is
            // greater than K then
            // return -1
            if (map.get(i) > k)
                return -1;
        }
 
        // Stores all total state
        int state = (1 << n) - 1;
 
        // Travere over all the state
        for (int i = 0; i <= state; i++) {
 
            // If number of set bit
            // is equal to N/K
            if (Integer.bitCount(i) == goal)
                bits.add(i);
        }
 
        // Stores the minimum value
        // at a state
        dp = new int[1 << n][k];
 
        // Intiallize the dp state
        // with -1
        for (int i = 0;
             i < dp.length; i++) {
            Arrays.fill(dp[i], -1);
        }
 
        // Call the recursive function
        return dfs(A, state, 0);
    }
 
    // Recursive function to find
    // the minimum required value
    public int dfs(int A[], int state,
                   int index)
    {
        // Base Case
        if (index >= k) {
            return 0;
        }
 
        // Stores the minimum value
        // of the current state
        int res = 1000;
 
        // If dp[state][index] is
        // already calculated
        if (dp[state][index] != -1) {
 
            // return dp[state][index]
            return dp[state][index];
        }
 
        // Traverse over all the bits
        for (int bit : bits) {
 
            // If count of set bit is N/K
            if (Integer.bitCount(bit)
                == goal) {
 
                // Store the new state after
                // choosing N/K elements
                int newstate = state;
 
                // Stores the minimum and
                // maximum of current subset
                int mn = 100, mx = -1;
 
                // Stores if the elements
                // have been already
                // selsected or not
                boolean visit[]
                    = new boolean[n + 1];
 
                // Stores if it is possible
                // to select N/K elements
                boolean good = true;
 
                // Traverse over the array
                for (int j = 0; j < n; j++) {
 
                    // If not chosen already
                    // for another subset
                    if ((bit & (1 << j)) != 0) {
 
                        // If already chosen
                        // for another subset
                        // or current subset
                        if (visit[A[j]] == true
                            || (state & (1 << j)) == 0) {
 
                            // Mark the good false
                            good = false;
                            break;
                        }
 
                        // Mark the current
                        // number visited
                        visit[A[j]] = true;
 
                        // Mark the current
                        // position in mask
                        // newstate
                        newstate = newstate
                                   ^ (1 << j);
 
                        // Update the maximum
                        // and minimum
                        mx = Math.max(mx,
                                      A[j]);
                        mn = Math.min(mn,
                                      A[j]);
                    }
                }
 
                // If good is true then
                // Update the res
                if (good) {
                    res = Math.min(
                        res, mx - mn
                                 + dfs(A, newstate,
                                       index + 1));
                }
            }
        }
 
        // Update the current sp state
        dp[state][index] = res;
 
        // Return the res
        return res;
    }
}
 
// Driver Code
class GFG {
 
    public static void main(String[] args)
    {
        Solution st = new Solution();
        int[] arr = { 1, 2, 1, 4 };
        int K = 2;
 
        // Function Call
        System.out.print(
            st.minimumIncompatibility(arr, K));
    }
}


C#
// C# program for the above approach
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
 
class Solution {
  int k;
  int n;
  int goal;
  int [,]dp;
  List bits = new List();
 
  // Function to find the minimum
  // incomatibility sum
  public int minimumIncompatibility(
    int[] A, int k)
  {
    this.n = A.Length;
    this.k = k;
    goal = n / k;
 
    // Stores the count of element
    Dictionary map
      = new Dictionary();
 
    // Traverse the array
    foreach(int i in A) {
 
      // If number i not occurs
      // in Map
      if (!map.ContainsKey(i))
 
        // Put the element
        // in the Map
        map[i]= 0;
 
      // Increment the count of
      // i in the Hash Map
      map[i]++;
 
      // If count of i in Map is
      // greater than K then
      // return -1
      if (map[i] > k)
        return -1;
    }
 
    // Stores all total state
    int state = (1 << n) - 1;
 
    // Travere over all the state
    for (int i = 0; i <= state; i++) {
 
      // If number of set bit
      // is equal to N/K
      if (Convert.ToString(i, 2).Count(c => c == '1') == goal)
        bits.Add(i);
    }
 
    // Stores the minimum value
    // at a state
    dp = new int[1 << n,k];
 
    // Intiallize the dp state
    // with -1
    for (int i = 0;i < dp.GetLength(0); i++) {
 
      for (int j = 0;j < dp.GetLength(1); j++) {
        dp[i,j]=-1;
      }
 
    }
 
    // Call the recursive function
    return dfs(A, state, 0);
  }
 
  // Recursive function to find
  // the minimum required value
  public int dfs(int []A, int state,
                 int index)
  {
    // Base Case
    if (index >= k) {
      return 0;
    }
 
    // Stores the minimum value
    // of the current state
    int res = 1000;
 
    // If dp[state][index] is
    // already calculated
    if (dp[state,index] != -1) {
 
      // return dp[state][index]
      return dp[state,index];
    }
 
    // Traverse over all the bits
    foreach(int bit in bits) {
 
      // If count of set bit is N/K
      if(Convert.ToString(bit, 2).Count(c => c == '1')== goal) {
 
        // Store the new state after
        // choosing N/K elements
        int newstate = state;
 
        // Stores the minimum and
        // maximum of current subset
        int mn = 100, mx = -1;
 
        // Stores if the elements
        // have been already
        // selsected or not
        bool []visit
          = new bool[n + 1];
 
        // Stores if it is possible
        // to select N/K elements
        bool good = true;
 
        // Traverse over the array
        for (int j = 0; j < n; j++) {
 
          // If not chosen already
          // for another subset
          if ((bit & (1 << j)) != 0) {
 
            // If already chosen
            // for another subset
            // or current subset
            if (visit[A[j]] == true
                || (state & (1 << j)) == 0) {
 
              // Mark the good false
              good = false;
              break;
            }
 
            // Mark the current
            // number visited
            visit[A[j]] = true;
 
            // Mark the current
            // position in mask
            // newstate
            newstate = newstate
              ^ (1 << j);
 
            // Update the maximum
            // and minimum
            mx = Math.Max(mx,
                          A[j]);
            mn = Math.Min(mn,
                          A[j]);
          }
        }
 
        // If good is true then
        // Update the res
        if (good) {
          res = Math.Min(
            res, mx - mn
            + dfs(A, newstate,
                  index + 1));
        }
      }
    }
 
    // Update the current sp state
    dp[state,index] = res;
 
    // Return the res
    return res;
  }
}
 
// Driver Code
class GFG {
 
  public static void Main()
  {
    Solution st = new Solution();
    int[] arr = { 1, 2, 1, 4 };
    int K = 2;
 
    // Function Call
    Console.Write(
      st.minimumIncompatibility(arr, K));
  }
}
 
// This code is contributed by rutvik_56.


输出:
4

时间复杂度: O(N 2 * 2 2 * N )
辅助空间: O(N)