unswitch while loop optimization in c - 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.

Related

need some printing number pyramid

I need to program a number pattern pyramid like that:
Here is my code:
#include<stdio.h>
int main()
{
int i, j, rows = 5;
for (i = 1; i <= 5; i++)
{
for (j = 1; j <= i; j++)
{
printf("%d ", j);
}
printf("\n");
}
for (i = 0; i <= 5; i++)
{
for (j = 0; j <= i; j++)
{
printf("%d ", j);
}
printf("\n");
}
}
Where am I doing wrong? I need to flip somehow the first triangle pattern and mix it with the second. Please help.
Your pyramid is 6 levels high. The max number is 5. This is not a coincidence. There is a direct relationship.
If n is 5, you need to do something 6 times, from 0 to n. There's a loop.
for (int i = 0; i <= n; i++) {
...
}
On each row you need to do print from i to 0, and then from 1 to i. That's two loops.
for (int j = i; j > 0; j--) {
...
}
for (int j = 1; j <= i; j++) {
...
}
Of course, you also need to indent a number of spaces inversely related to i, which is another loop.
for (int j = 0; j <= /* Fill in here for inverse relationship */; j++) {
...
}
I need to flip somehow the first triangle pattern and mix it with the second.
TL;DR The trick is very simple: your row index i should start from |n - j| (or abs(n - j)) where j is the column index and n is the number.
Here is how you can do it:
for (int j = 0; j < ncols; ++j) {
for (int i = abs(n - j); i < nrows; ++i) {
matrix[i][j] = '0' + abs(n - j);
}
}
Explanation:
Imagine you have a matrix. In order to build a pyramid with a number n, you will need:
n + 1 rows (since you will have 0 included in the top). Let's call it nrows.
2n + 1 columns (2n because the numbers will appear twice in a row, 1 because you will have one 0 per row). Let's call it ncols.
0 1 2 3 4 5 6 7 8 9 10
- - - - - - - - - - -
0 | 0
1 | 1 0 1
2 | 2 1 0 1 2
3 | 3 2 1 0 1 2 3
4 | 4 3 2 1 0 1 2 3 4
5 | 5 4 3 2 1 0 1 2 3 4 5
First, you want to fill the first half, i.e. from column 0 to n: for (int j = 0; j <= n; ++j).
J | End | Start | Pattern of Start
---------------------------------------
0 | N | N | N - 0
---------------------------------------
1 | N | N - 1 | N - 1
---------------------------------------
2 | N | N - 2 | N - 2
---------------------------------------
... | ... | ..... | N - J
---------------------------------------
N | N | 0 | N - N
The pattern is: for (int i = n - j; i < nrows; ++i). You would fill that first half with n - j.
Second, you want to fill the second half, i.e. from column n + 1 to 2n: for (int j = n + 1; j < ncols; ++j).
J | End | Start | Pattern of Start
------------------------------------------
N + 1 | N | 1 | N + 1 - N = J - N
------------------------------------------
N + 2 | N | 2 | N + 2 - N = J - N
------------------------------------------
N + 3 | N | 3 | N + 3 - N = J - N
------------------------------------------
..... | ... | ..... | N + X - N = J - N
------------------------------------------
2N | N | N | 2N - N = J - N
The pattern is: for (int i = j - n; i < nrows; ++i). You would fill that second half with j - n.
Now, you can do two separate for loops to fill the first and second halves.
// Fill first half
for (int j = 0; j <= n; ++j) {
for (int i = n - j; i < nrows; ++i) {
matrix[i][j] = '0' + n - j;
}
}
// Fill second half
for (int j = n + 1; j < ncols; ++j) {
for (int i = j - n; i < nrows; ++i) {
matrix[i][j] = '0' + j - n;
}
}
You can write one for loop by replacing n - j and j - n with abs(n - j), since both of them are positive values (see TL;DR above, or the code below).
Full functionning code:
#include <stdio.h>
#include <stdlib.h>
void print_matrix(const int nrows, const int ncols, const char matrix[nrows][ncols])
{
for (int i = 0; i < nrows; ++i) {
for (int j = 0; j < ncols; ++j)
printf("%c ", matrix[i][j]);
printf("\n");
}
}
void init_matrix(const int nrows, const int ncols, char matrix[nrows][ncols], const char value)
{
for (int i = 0; i < nrows; ++i)
for (int j = 0; j < ncols; ++j)
matrix[i][j] = value;
}
void print_pyramid(const int n)
{
// Calculate the number of rows and columns
const int nrows = n + 1;
const int ncols = n * 2 + 1;
char matrix[nrows][ncols];
// Initialization
init_matrix(nrows, ncols, matrix, '\0');
// Fill the matrix
for (int j = 0; j < ncols; ++j) {
for (int i = abs(n - j); i < nrows; ++i) {
matrix[i][j] = '0' + abs(n - j);
}
}
// Printing
print_matrix(nrows, ncols, matrix);
}
int main(void)
{
print_pyramid(5);
}
You have to include all 3 for loops in one for loop which runs 6 times. First you have to print spaces. Then first half of the triangle and then the other half. After that you have to print \n .
#include<stdio.h>
int main()
{
int i, j,k,l;
for (i = 0; i <=5; i++)
{
for (j = 5; j > i; j--)
{
printf(" ");
}
for (k = i; k >=0; k--)
{
printf("%d ", k);
}
for (l = 1; l <=i; l++)
{
printf("%d ", l);
}
printf("\n");
}
}

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();
}

Minimum sum partition of an array

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

Resources