Split a binary string into K subsets minimizing sum of products of occurrences of 0 and 1


A binary string is made up of a succession of binary numbers, also known as bits, that are either 0 or 1. It is a method of encoding data that uses only two numbers for computer applications where data is stored and processed using electronic circuits that can only recognise two states. In computer programming, binary strings are frequently used to represent data in way that is simple for electronic circuits to handle, such as numbers, text, and images.

Method

Method 1. Dynamic Programming

Method 2. Greedy Approach

Method 1: Dynamic Programming

To tackle this difficulty, we can employ dynamic programming. Let dp [i] [j] be smallest sum of products for first i characters of binary string divided into j subsets. By testing all doable split focuses k (1 = k I) and afterward registering dp [i] [j], we might decide the base of dp[k] [j-1] + cost[k+1] [i], where cost[k+1] [i] is the expense of partitioning the substring from k+1 to I. The not set in stone by duplicating the quantity of 0s and 1s in the substring.

Syntax

A syntax of the dynamic programming approach is provided below −

  • Make 2D table called dp with dimensions K+1 by n+1, where K is number of subsets and n is length of binary string. When first j characters of binary string are divided into i subsets, dp[i][j] reflects least sum of products of 0 and 1.

  • Initialise the base cases−

    • dp[1][j] is binary string's first j characters' sum of all instances of 0 and 1.

    • dp[i][i] is 0 for every i (because there is only one subset when splitting a string of length i).

  • Find dp[i][j] for each i from 2 to K and each j from i+1 to n using the recurrence relation: dp[i][j] = min(dp[i-1][k] + cost[k+1][j] here cost[k+1][j] is product of all 0 and 1 for the substring from k+1 to j. By iterating over all conceivable values of k from i-2 to j-2, one may determine least value of dp[i][j].

  • When binary string is divided into K subsets, dp[K][n] provides minimum sum of products of 0 and 1.

Algorithm

Step 1 − Array of sides (K+1)* (n+1) of binary string .

Step 2− Set base case's initial conditions to dp[0][0] = 0, dp[i][0] = infinity for i > 0, and dp[0][j] = infinity for j > 0.

Step 3 − Calculate dp[i][j] for each i from 1 to n and each j from 1 to K−

  • Take minimum of all such costs as dp[i][j].

  • For each k from 0 to i-1, compute cost of splitting binary string from k to i-1 into j-1 subsets and add product of the number of 0s and 1s in that substring.

Step 4 − Provide dp[n][K] as least expensive way to divide binary string into K subsets.

Example 1

As first step, we add up all binary string's conceivable substrings, storing results in sum array. The minimum sum of products is then stored in dp array after binary string is divided into k subsets up to i-th character.

#include <iostream>		
#include <cstring>
#include <climits>
using namespace std;

const int MAXN = 105;
const int INF = INT_MAX;

int dp[MAXN][MAXN], sum[MAXN][MAXN];

int main() {
   string s = "1001011101"; 
   int K = 3; 
   int n = s.length();
   memset(dp, 0, sizeof(dp));
   memset(sum, 0, sizeof(sum));
   for (int i = 1; i <= n; i++) {
      sum[i][i] = s[i - 1] - '0';
      for (int j = i + 1; j <= n; j++) {
         sum[i][j] = sum[i][j - 1] + s[j - 1] - '0';
      }
   }
   for (int k = 1; k <= K; k++) {
      for (int i = 1; i <= n; i++) {
         if (k == 1) {  
            dp[i][k] = sum[1][i] * (sum[1][n] - sum[i][n]);
         } else {
           dp[i][k] = INF;
            for (int j = 1; j < i; j++) {
              dp[i][k] = min(dp[i][k], dp[j][k - 1] + sum[j + 1][i] * (sum[1][n] - sum[i][n]));
            }
         }
      }
   }
   cout << "Minimum sum of products: " << dp[n][K] << endl;
   return 0;
}

Output

Minimum sum of products: -2147483624

Method 2: Greedy Approach

We can begin by splitting the binary string into K equal pieces. The cost of each component may then be determined, and by exchanging nearby components, we can strive to reduce the overall cost. Up until there are no more viable swaps or there is no more cost savings, we can switch nearby pieces.

Syntax

  • Given binary string s and integer K

  • length of binary string s

int n = s.length(); 
  • cut[i] = count of 1's in first i bits of s

vector<int> cut(a+1);
for (int D = 0; D < a; D++) {
   cut[D+1] = cut[D] + (s[D] == '1');
}
vector<int> ft(a+1, 1e9); 
ft[0] = 0;
for (int R = 1; k <= R; R++) {
   for (int D = a; D >= R; D--) {
      for (int j = R-1; j < R; j++) {
         dp[D] = min(ft[D], ft[j] + (cut[D] - cut[j]) * (cut[j] - cut[R-1]));
      }
   }
}
  • minimum sum of products of 0's and 1's in s split into K subsets

int ans = ft[a]; 

Algorithm for greedy method

Step 1 − Determine the binary string's 0 and 1 count.

Step 2 − Subtract the digits of 0s from the digits of 1s.

Step 3 − Split the binary string into K equal sections.

Step 4 − Count how many 0s and 1s there are in every segment.

Step 5 − Subtract the digits of 0s from the digits of 1s for each segment.

Step 6 − Total product is obtained by adding all section products.

Step 7 − Return segments as a solution if the total product is smaller than that determined in step 2 of the calculation. Go to step 8 if not.

Step 8 − Continue until K segments are obtained by merging neighbouring segments that have the least sum of products of 0s and 1s.

Example 2

Following that, the string is parted into K subsets by emphasizing through each letter and adding it to the ongoing subset assuming the all out number of redundancies of 0 and 1 isn't negative.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
vector<string> splitBinaryString(string s, int k) {
   vector<int> zeros(s.length()), ones(s.length());
   int zeroCount = 0, oneCount = 0;
   for (int i = s.length() - 1; i >= 0; i--) {
      if (s[i] == '0') zeroCount++;
      else oneCount++;
      zeros[i] = zeroCount;
      ones[i] = oneCount;
   }
   vector<string> subsets(k);
   for (int i = 0; i < k; i++) {
      subsets[i] = "";
      int start = i, end = s.length() - k + i + 1;
      for (int j = start; j < end; j++) {
         int zeroOccurrences = zeros[j] - zeros[start];
         int oneOccurrences = ones[j] - ones[start];
         if (zeroOccurrences * oneOccurrences < 0) break;
         subsets[i] += s[j];
      }
   }
   return subsets;
}
int sumOfProducts(vector<string> subsets) {
   int sum = 0;
   for (string subset : subsets) {
      int zeroCount = count(subset.begin(), subset.end(), '0');
      int oneCount = subset.length() - zeroCount;
      sum += zeroCount * oneCount;
   }
   return sum;
}
int main() {
   string s = "1010110010";
   int k = 3;
   vector<string> subsets = splitBinaryString(s, k);
   int result = sumOfProducts(subsets);
   cout << "Minimum sum of products of occurrences of 0 and 1: " << result << endl;
   return 0;
}

Output

Minimum sum of products of occurrences of 0 and 1: 48

Conclusion

Dynamic programming can be used to find the smallest sum of products of 0 and 1 when dividing binary string to K subsets. We can quickly determine minimal cost full string by keeping track of minimum costs for each subset size and each starting location. The dynamic programming method temporal complexity of O (K * n2), where n is length of binary string.

Updated on: 31-Jul-2023

74 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements