Minimum sum partition of an array - c

Problem Statement:
Given an array, the task is to divide it into two sets S1 and S2 such that the absolute difference between their sums is minimum.
Sample Inputs,
[1,6,5,11] => 1. The 2 subsets are {1,5,6} and {11} with sums being 12 and 11. Hence answer is 1.
[36,7,46,40] => 23. The 2 subsets are {7,46} and {36,40} with sums being 53 and 76. Hence answer is 23.
Constraints
1 <= size of array <= 50
1 <= a[i] <= 50
My Effort:
int someFunction(int n, int *arr) {
qsort(arr, n, sizeof(int), compare);// sorted it for simplicity
int i, j;
int dp[55][3000]; // sum of the array won't go beyond 3000 and size of array is less than or equal to 50(for the rows)
// initialize
for (i = 0; i < 55; ++i) {
for (j = 0; j < 3000; ++j)
dp[i][j] = 0;
}
int sum = 0;
for (i = 0; i < n; ++i)
sum += arr[i];
for (i = 0; i < n; ++i) {
for (j = 0; j <= sum; ++j) {
dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
if (j >= arr[i])
dp[i + 1][j + 1] = max(dp[i + 1][j + 1], arr[i] + dp[i][j + 1 - arr[i]]);
}
}
for (i = 0; i < n; ++i) {
for (j = 0; j <= sum; ++j)
printf("%d ", dp[i + 1][j + 1]);
printf("\n");
}
return 0;// irrelevant for now as I am yet to understand what to do next to get the minimum.
}
OUTPUT
Let's say for input [1,5,6,11], I am getting the dp array output as below.
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
0 1 1 1 1 5 6 7 7 7 7 11 12 12 12 12 12 12 12 12 12 12 12 12
0 1 1 1 1 5 6 7 7 7 7 11 12 12 12 12 16 17 18 18 18 18 22 23
Now, how to decide the 2 subsets to get the minimum?
P.S - I have already seen this link but explanation is not good enough for a DP beginner like me.

You have to solve subset sum problem for SumValue = OverallSum / 2
Note that you don't need to solve any optimization problem (as using max operation in your code reveals).
Just fill linear table (1D array A) of size (SumValue + 1) with possible sums, get the closest to the last cell non-zero result (scan A backward) wint index M and calculate final result as abs(OverallSum - M - M).
To start, set 0-th entry to 1.
Then for every source array item D[i] scan array A from the end to beginning:
A[0] = 1;
for (i = 0; i < D.Length(); i++)
{
for (j = SumValue; j >= D[i]; j--)
{
if (A[j - D[i]] == 1)
// we can compose sum j from D[i] and previously made sum
A[j] = 1;
}
}
For example D = [1,6,5,11] you have SumValue = 12, make array A[13], and calculate possible sums
A array after filling: [0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1]
working Python code:
def besthalf(d):
s = sum(d)
half = s // 2
a = [1] + [0] * half
for v in d:
for j in range(half, v - 1, -1):
if (a[j -v] == 1):
a[j] = 1
for j in range(half, 0, -1):
if (a[j] == 1):
m = j
break
return(s - 2 * m)
print(besthalf([1,5,6,11]))
print(besthalf([1,1,1,50]))
>>1
>>47

I'll convert this problem to subset sum problem
let's take array int[] A = { 10,20,15,5,25,33 };
it should be divided into {25 20 10} and { 33 20 } and answer is 55-53=2
Notations : SUM == sum of whole array
sum1 == sum of subset1
sum2 == sum of subset1
step 1: get sum of whole array SUM=108
step 2: whichever way we divide our array into two part one thing will remain true
sum1+ sum2= SUM
step 3: if our intention is to get minimum sum difference then
sum1 and sum2 should be near SUM/2 (example sum1=54 and sum2=54 then diff=0 )
steon 4: let's try combinations
sum1 = 54 AND sum2 = 54 (not possible to divide like this)
sum1 = 55 AND sum2 = 53 (possible and our solution, should break here)
sum1 = 56 AND sum2 = 52
sum1 = 57 AND sum2 = 51 .......so on
pseudo code
SUM=Array.sum();
sum1 = SUM/2;
sum2 = SUM-sum1;
while(true){
if(subSetSuMProblem(A,sum1) && subSetSuMProblem(A,sum2){
print "possible"
break;
}
else{
sum1++;
sum2--;
}
}
Java code for the same
import java.util.ArrayList;
import java.util.List;
public class MinimumSumSubsetPrint {
public static void main(String[] args) {
int[] A = {10, 20, 15, 5, 25, 32};
int sum = 0;
for (int i = 0; i < A.length; i++) {
sum += A[i];
}
subsetSumDynamic(A, sum);
}
private static boolean subsetSumDynamic(int[] A, int sum) {
int n = A.length;
boolean[][] T = new boolean[n + 1][sum + 1];
// sum2[0][0]=true;
for (int i = 0; i <= n; i++) {
T[i][0] = true;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum; j++) {
if (A[i - 1] > j) {
T[i][j] = T[i - 1][j];
} else {
T[i][j] = T[i - 1][j] || T[i - 1][j - A[i - 1]];
}
}
}
int sum1 = sum / 2;
int sum2 = sum - sum1;
while (true) {
if (T[n][sum1] && T[n][sum2]) {
printSubsets(T, sum1, n, A);
printSubsets(T, sum2, n, A);
break;
} else {
sum1 = sum1 - 1;
sum2 = sum - sum1;
System.out.println(sum1 + ":" + sum2);
}
}
return T[n][sum];
}
private static void printSubsets(boolean[][] T, int sum, int n, int[] A) {
List<Integer> sumvals = new ArrayList<Integer>();
int i = n;
int j = sum;
while (i > 0 && j > 0) {
if (T[i][j] == T[i - 1][j]) {
i--;
} else {
sumvals.add(A[i - 1]);
j = j - A[i - 1];
i--;
}
}
System.out.println();
for (int p : sumvals) {
System.out.print(p + " ");
}
System.out.println();
}
}

Working Java code if anyone is interested but the idea remains the same as what #MBo has answered
class Solution{
public int minDifference(int arr[]) {
int sum = 0;
for(int x : arr) sum += x;
int half = (sum >> 1) + (sum & 1);
boolean[] sums = new boolean[half + 1];
sums[0] = true;
for(int i = 0; i < arr.length; ++i){
if(arr[i] > half) continue;
for(int j = half; j >= arr[i]; --j){
if(sums[j - arr[i]]){
sums[j] = true;
}
}
}
for(int i = sums.length - 1; i >= 1; --i){
if(sums[i]) return Math.abs((sum - i) - i);
}
return sum; // for arrays like [2] or [100] etc
}
}

Related

Sorting a 2D Array c++

I am bubble sorting a 2D array that looks like this. I am confuse on how to make my largest value as 1 and make the 2nd row's value follow to 1st row's counterpart.
Input:
13 9 1 8 5
1 2 3 4 1
Actual output:
1 5 8 9 13
1 2 3 4 1
This is the expected output that i am trying to make.
Output:
5 8 9 13 1
1 4 2 1 1
Here is my code for sorting the cards (col = 5 and row = 2):
void sortedCards(int card[][col])
{
int i, j, k, temp;
printf("\n\nSorted Cards\n");
for (k = 0; k < 10; k++)
{
for (i = 0; i < row - 1; i++)
{
for (j = 0; j < col - 1; j++)
{
if (card[i][j] > card[i][j + 1])
{
temp = card[i][j];
card[i][j] = card[i][j + 1];
card[i][j + 1] = temp;
}
}
}
}
for (i = 0; i < row; i++)
{
if (i == 1)
{
printf("\n");
}
for (j = 0; j < col; j++)
{
printf("%i ", card[i][j]);
}
}
}
If your sorting is only dependent on the first row, there is no need to iterate through the second row. Just set both rows at the same time while checking the first row.
Also, if you want 1 to be treated as larger than all other numbers, you need to add that to your Boolean logic. Adjusting your for loop like below should do it.
int j, k, temp, temp2;
for (k = 0; k < 10; k++)
{
for (j = 0; j < col-1; j++)
{
//here we only test row 0, and we check if the value is 1
if (card[0][j] == 1 || (card[0][j] > card[0][j+1] && card[0][j+1] != 1))
{
//all other reassignment is the same but you do both rows at the same time
temp = card[0][j];
temp2 = card[1][j];
card[0][j] = card[0][j + 1];
card[1][j] = card[1][j + 1];
card[0][j + 1] = temp;
card[1][j + 1] = temp2;
}
}
}

Divide an array into subarrays so that sum of product of their length and XOR is minimum

We have an array of "n" numbers. We need to divide it in M subarray such that the cost is minimum.
Cost = (XOR of subarray) X ( length of subarray )
Eg:
array = [11,11,11,24,26,100]
M = 3
OUTPUT => 119
Explanation:
Dividing into subarrays as = > [11] , [11,11,24,26] , [100]
As 11*1 + (11^11^24^26)*4 + 100*1 => 119 is minimum value.
Eg2: array = [12,12]
M = 1
output: 0
As [12,12] one way and (12^12)*2 = 0.
You can solve this problem by using dynamic programming.
Let's define dp[i][j]: the minimum cost for solving this problem when you only have the first i elements of the array and you want to split (partition) them into j subarrays.
dp[i][j] = cost of the last subarray plus cost of the partitioning of the other part of the given array into j-1 subarrays
This is my solution which runs in O(m * n^2):
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000 + 10;
const int MAXM = 1000 + 10;
const long long INF = 1e18 + 10;
int n, m, a[MAXN];
long long dp[MAXN][MAXM];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// start of initialization
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
dp[i][j] = INF;
dp[0][0] = 0;
// end of initialization
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int last_subarray_xor = 0, last_subarray_length = 0;
for (int k = i; k >= 1; k--) {
last_subarray_xor ^= a[k];
last_subarray_length = i - k + 1;
dp[i][j] = min(dp[i][j], dp[k - 1][j - 1] + (long long)last_subarray_xor * (long long)last_subarray_length);
}
}
}
cout << dp[n][m] << endl;
return 0;
}
Sample input:
6 3
11 11 11 24 26 100
Sample output:
119
One of the most simple classic dynamic programming problems is called "0-1 Knapsack" that's available on Wikipedia.

Count Number of distinct subarrays

I recently came across this question in one of the coding interviews. The question is as follows:
Given an array A[] of n numbers and a number k, count the total number of distinct subarrays such that each subarray contains at most k odd elements.
1 <= n <= 1000
1 <= A[i] <= 250
1 <= k <= n
I used a DP approach to solve the problem, but my solution does not take care of the distinct part.
public int distinctSubArraysWithAtmostKOddElements(int[] a, int k) {
int l = a.length;
int[][] dp = new int[k + 1][l];
for (int j = 0; j < l; j++) {
dp[0][j] = a[j] % 2 == 0 ? 1 : 0;
}
for (int i = 1; i <= k; i++) {
dp[i][0] = 1;
}
for (int j = 1; j <= k; j++) {
for (int i = 1; i < l; i++) {
if (a[i] % 2 == 0) {
dp[j][i] = Math.max(dp[j - 1][i], 1 + Math.max(dp[j - 1][i - 1], dp[j][i - 1]));
} else {
dp[j][i] = Math.max(dp[j - 1][i], 1 + dp[j - 1][i - 1]);
}
}
}
int tot = 0;
for (int i = 0; i < l; i++) {
tot += dp[k][i];
}
return tot;
}
My solution works in O(nk) time and space.
How can I take care of the distinctness ? Is there a mathematical formula that solves this problem?
Edit:
Eg 1:
A[] = {2,1,2,3} and k = 1
Distinct Subarrays are: {2}, {2,1}, {1}, {1,2}, {2,1,2}, {3}, {2,3}
So answer is 7.
Eg 2:
A[] = {1,1,1} and k = 2
Distinct Subarrays are: {1}, {1,1}
So answer is 2.
Eg 3:
A[] = {1,2,3} and k = 1
Distinct Subarrays are: {1}, {2}, {3}, {1,2}, {2,3}
So answer is 5.
We can iterate over all subarrays and store the hashes of the valid subarrays.The time complexity is O((n^2)*log(n)) and memory complexity O(n^2).
int distinctSubArraysWithAtmostKOddElements(vector<int> a, int k)
{
set<unsigned long long int> hashes;
int prime = 163;
for(int i = 0 ; i < a.size() ; i++)
{
int oddNow = 0;
unsigned long long int hashNow = 0;
for(int j = i ; j < a.size() ; j++)
{
hashNow = hashNow * prime + a[j];
if( a[j] % 2) oddNow++;
if(oddNow <= k)
hashes.insert(hashNow);
else
break;
}
}
return hashes.size();
}

How can I calculate the moving average of the array?

In Question, When an array X of size n and a degree k are input,
Write a program that calculates the k-th moving average of array X.
The kth-order moving average of the array X consisting of primitive data values is the average of the last k elements up to the i-th point of X.
That is, A [i] = (X [i-k + 1] + X [i-k + 2] + ... + X [i]) / k.
If the number of the preceding element (including itself) is smaller than k,
Calculate as an average.
For example, if array X is as follows and k is 3, X = 1 3 2 10 6 8
The third moving average is as follows.
A = 1 2 2 5 6 8 A [1] = (1 + 3) / 2, A [2] = (1 + 3 + 2) / 3
However, the program must have the execution time of O (n), not O (nk).
Round off the decimal point in the average calculation and obtain it as an integer.
For exact rounding, do not use% .f, but round it using the int property.
int main()
{
int i, n1, k;
int *array1;
scanf("%d", &n1);
array1 = (int *)malloc(sizeof(int)*n1);
scanf("%d", &k);
for (i = 0; i < n1; i++)
{
scanf("%d", &array1[i]);
}
double tmp = 0;
for (int i = 0; i < n1; i++)
{
tmp += array1[i];
if (i >= k)
{
tmp -= array1[i - k];
}
if (i >= k - 1)
{
double average = tmp / k;
printf("%2lld ", llrint(average));
}
return 0;
}
The program does not work because the problem is not understood.
I would like to know how to solve it.
add) Thank you for answer but the output required by the problem is as follows.
Input : 9 4 (n = 9, k = 3)
2 7 4 5 6 8 2 8 13
Output : 2 5 4 5 6 6 5 6 8
After Modifying your code
int main()
{
int i, n1, k;
int *array1, *array2;
scanf("%d", &n1);
array1 = (int *)malloc(sizeof(int)*n1);
scanf("%d", &k);
for (i = 0; i < n1; i++)
{
scanf("%d", &array1[i]);
}
double tmp = 0;
for (int i = 0; i < n1; i++)
{
tmp += array1[i];
// now tmp contains exactly k + 1 elements sum
// so subtract elements outside of k sized window(leftmost element)
if(i >= k) {
tmp -= array1[i - k];
}
if(i >= k - 1) {
double average = tmp / k;
printf("%lf\n", average);
}
}
return 0;
}

unswitch while loop optimization in c

I'm having a hard time optimizing the following while loop by means of Loop Unswitching. I have tried applying the example from wiki, however I am having a hard time applying it to a while loop. I have the following code:
int n = 5,
m = 5,
i = 0,
val = 0;
while (i < n ) {
j = 0;
while (j < m ) {
if (i < j ) {
val = val + i ;
}
else if ( j == i ) {
val = val - 1;
}
else {
val = val + j ;
}
j = j + 1;
}
i = i + 1;
}
And have tried unswitching it the following way:
while (i < n ) {
j = 0;
if (i < j ) {
while (j < m ) {
val = val + i;
j = j + 1;
}
}
if ( j == i ) {
while (j < m) {
val = val - 1;
j = j + 1;
}
}
if (i > j) {
while (j < m) {
val = val + j;
j = j + 1;
}
}
i = i + 1;
}
What could I be doing wrong.
Such loops are best unrolled with the help of pencil and paper. You want the sum of the following grid:
0 1 2 3 4 | 5 n
0 -1 0 0 0 0 | 0 0
1 0 -1 1 1 1 | 1 1
2 0 1 -1 2 2 | 2 2
3 0 1 2 -1 3 | 3 3
m 0 1 2 3 -1 | 4 4
The grid can be subdivided into three parts: the diagonal, the upper and lower triangles next to the diagonal in the square part and the rectangular block when n and m differ.
Let's represent the dimension of the grid by means of the square part, k² and the rectangular part, k·r:
k = min(n, m)
r = max(m, n) - k
Now you can see which sums the three parts contribute:
val = 2·∑(k - i - 1)·i # two triangles
+ r·∑(i) # rectangle
- k # diagonal
(All sums run from i = 0; i < n; i++.) This sum can be rearranged to:
val = 2·(k - 1)·∑(i) - 2*∑(i²) + r·(i) - k
= (2·k + r - 2)·∑(i) - 2*∑(i²) - k
This reduces your two nested loops two two independent loops to do the sums of the natural numbers and of their squares. Fortunately, these sums can be expressed by simple relations:
∑(i) = (n - 1)·n / 2
∑(i²) = (2·n - 1)·(n - 1)·n / 6
You now have a constant-time formula for your resulting sum:
int val(int n, int m)
{
int k = (n < m) ? n : m;
int r = ((n > m) ? n : m) - k;
return (2*k + r - 2) * (k - 1) * k / 2
- (2*k - 1) * k * (k - 1) / 3 - k;
}
All this doesn't have anything to do with loop unrolling, of course.
Loop unswitching according to wikipedia is a compiler optimization so I'm a little confused about why you'd need to do this yourself, but I think this is as good as it gets in terms of breaking apart the for..ifs
for (i = 0; i < n; ++i) {
// j < i
for (j = 0; j < i; ++j) {
val = val + j;
}
// j == i
val = val - 1;
// j > i
for (j = i + 1; j < m; ++j) {
val = val + i;
}
}
This is not a loop you can traditionally unswitch because the conditional variable here is the loop variable.

Resources