How to turn equation with decrementing indexing into math equation with summation? - c++

Similar to this question: Turn while loop into math equation?, I have the following nested loop that I am trying to convert into a math equation as I need to write this up in a format that doesn't look like code. I believe I am going to need some type of summation equation.
Here is the code:
int num = 0;
for (int i = nr - 1; i >= 0; i--) {
for (int j = nc - 1; j >= 0; j--) {
ela[i][j] = num;
eha[i][j] = num + ea[i][j] - 1;
num += ea[i][j];
}
}
I know that summations start from a lower bound and continue to a higher bound, so I'm not quite sure how to apply a summation here since I start from a higher index and continue to a lower index.
I'm not sure why I'm getting downvoted, as the question I referenced is very similar to mine, has the same tags and is upvoted 14 times. Please comment below if I can improve my question somehow.
Update:
I was able to update the formula as follows:
nr = 50;
nc = 10;
num = sum[ea[i,j],i=0,nr-1,j=0,nc-1]; // correct based upon nr, nc and ea
for (int i = 0; i < nr; i) {
for (int j = 0; j < nc; j++) {
num = num - ea[i,j];
ela[i][j] = num;
eha[i][j] = num + ea[i,j] - 1;
}
}

If I am right, you can transcribe the effect as
You can describe this as the matrix ela being a 2D suffix sum of the matrix ea (for every element, sum of the elements that follow in the lexicographical ordering), while eha is the sum of matrices ela and ea minus all ones.

If the problem is just with how to express the sum when you're looping the other direction, you can change your code to:
int num = 0;
for (int i = 0; i < nr; i++) {
for (int j = 0; j < nc; j++) {
ela[nr - i][nc - j] = num;
eha[nr - i][nc - i] = num + ea[nr - i][nc - j] - 1;
num += ea[nr - i][nc - j];
}
}
I'm not saying you have to change your code to this, but from here it should be more obvious how to change this to use summation notation.

It's hard to tell without any context, but the code in question becomes more intelligible if you think of the arrays as vectors enumerating the elements in reverse order, row-major. The code below is functionally equivalent to the original one posted, but arguably easier to follow.
// n.b. ela[nr - 1 - i][nc - 1 - j] == rela(nc * i + j);
int &rela(int k) { return ela[nr - 1 - k / nc][nc - 1 - k % nc]; }
int &reha(int k) { return elh[nr - 1 - k / nc][nc - 1 - k % nc]; }
int &rea(int k) { return ea[nr - 1 - k / nc][nc - 1 - k % nc]; }
for (int k = 0, sum = 0; k < nr * nc - 1; k++) {
rela(k) = sum;
sum += rea(k);
reha(k) = sum - 1;
}
In plain English, rela(k) is the partial sum of rea elements 0 ... k-1 and reha(k) is one less than the partial sum of rea elements 0 ... k (also, rela(k) == reha(k - 1) + 1 for k > 0).
Technically, this description could be translated back in terms of the 2d arrays, but it becomes rather messy quickly.

Related

Min sum of distances (absolute differences) between array element and set of k array elements

I need to find the minimum sum of the distances between an element in the array and the set of k-elements of the array, not including that index.
For example:
arr = {5, 7, 4, 9}
k = 2
min_sum(5) = |5-4| + |5-7| = 3
min_sum(7) = |7-9| + |7-5| = 4
min_sum(4) = |4-5| + |4-7| = 4
min_sum(9) = |9-7| + |9-5| = 6
So, a naive solution would be to subtract the i-th element from each element of the array, then sort the array and calculate the sum of the first k elements in the sorted array. But it takes too long... I believe this is a dp-problem or something like that (maybe treaps).
Input:
n - number of array elements
k - number of elements in a set
array
Constraints:
2 <= n <= 350 000
1 <= k < n
1 <= a[i] <= 10^9
time limit: 2 seconds
Input:
4
2
5 7 4 9
Output:
3 4 4 6
What is the most efficient way to solve this problem? How to optimize the search for the minimum sum?
This is my code in C++, and it works about 3 mins for n = 350 000, k = 150 000:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, tp;
unsigned long long temp;
cin >> n >> k;
vector<unsigned int> org;
vector<unsigned int> a;
vector<unsigned long long> cum(n, 0);
//unordered_map <int, long long> ans;
unordered_map <int, long long> mp;
for (int i = 0; i < n; i++){
cin >> tp;
org.push_back(tp);
a.push_back(tp);
}
/*
srand(time(0));
for (int i = 0; i < n; i++){
org.push_back(rand());
a.push_back(org[i]);
}
*/
sort(a.begin(), a.end());
partial_sum(a.begin(), a.end(), cum.begin());
mp[a[0]] = cum[k] - cum[0] - a[0] * k;
//ans[a[0]] = mp[a[0]];
for (int i = 1; i <= k; i++) {
mp[a[i]] = a[i] * i - cum[i-1] + cum[k] - cum[i] - a[i] * (k-i);
}
for (int i = 1; i < n-k; i++){
for (int j = 0; j <= k; j++){
//if (ans.find(a[i+j]) != ans.end()) {continue;}
temp = ( (a[i+j] * j) - (cum[i+j-1] - cum[i-1]) ) + ( cum[i+k] - cum[i+j] - a[i+j] * (k-j) );
if (mp.find(a[i+j]) == mp.end()) { mp[a[i+j]] = temp; }
else if (mp[a[i+j]] > temp) { mp[a[i+j]] = temp; }
//else { ans[a[i+j]] = mp[a[i+j]]; }
}
}
for (int i = 0; i < n; i++) {
cout << mp[org[i]] << " ";
}
return 0;
}
We can solve this problem efficiently by taking the sliding window approach.
It seems safe to assume that there are no duplicates in the array. If it contains duplicates, then we can simply discard them with the help of HashSet.
The next step is to sort the array to guarantee that the closest k elements will be within the window [i - k; i + k] for each index i.
We will keep three variables for the window: left, right and currentSum. They will be adjusted accordingly at each iteration. Initially, left = 0 and right = k(since the element at index 0 doesn't have elements to its left) and currentSum = result for index 0.
The key consideration is that the variables left and right are unlikely to change 'significantly' during the iteration. To be more precise, at each iteration we should attempt to move the window to the right by comparing the distances nums[i + right + 1] - nums[i] vs nums[i] - nums[i - left]. (You can prove mathematically that there is no point in trying to move the window to the left.) If the former is less than the latter, we increment right and decrement left while updating currentSum at the same time.
In order to recalculate currentSum, I would suggest writing down expressions for two adjacent iterations and looking closer at the difference between them.
For instance, if
result[i] = nums[i + 1] + ... + nums[i + right] - (nums[i - 1] + ... + nums[i - left]) + (left - right) * nums[i], then
result[i] = nums[i + 2] + ... + nums[i + right] - (nums[i] + ... + nums[i - left]) + (left - right + 2) * nums[i + 1].
As we can see, these expressions are quite similar. The time complexity of this solution is O(n * log(n)). (my solution in Java for n ~ 500_000 and k ~ 400_000 works within 300 ms) I hope this together with the consideration above will help you.
Assuming that we have sorted the original array nums and computed the mapping element->its index in the sorted array(for instance, through binary search), we can proceed with finding the distances.
public long[] findMinDistances(int[] nums, int k) {
long[] result = new long[nums.length];
long currentSum = 0;
for (int i = 1; i <= k; i++) {
currentSum += nums[i];
}
result[0] = currentSum - (long) k * nums[0];
int left = 0;
int right = k;
currentSum = result[0];
for (int i = 1; i < nums.length; i++) {
int current = nums[i];
int previous = nums[i - 1];
currentSum -= (long) (left - right) * previous;
currentSum -= previous;
if (right >= 1) {
currentSum -= current;
left++;
right--;
} else {
currentSum += nums[i - 1 - left];
}
currentSum += (long) (left - right) * current;
while (i + right + 1 < nums.length && i - left >= 0 &&
nums[i + right + 1] - current < current - nums[i - left]) {
currentSum += nums[i + right + 1] - current;
currentSum -= current - nums[i - left];
right++;
left--;
}
result[i] = currentSum;
}
return result;
}
For every element e in the original array its minimal sum of distances will be result[mapping.get(e)].
I think this one is better:
Sort the array first then you can know that fact -
For every element i in the array the k minimum distances of it with other elemets will be the distances with the ones that in k places around it in the array.
(of course it's maybe to the right or to the left or from both sides).
So for every element i to calculate min_sum(a[i]) do that:
First, min_sum(a[i]) = 0.
Then, go with two indexes, let's mark them r (to the right of i) and l (to the left of i)
and compare the distance (a[i]-a[r]) with the distance (a[i]-a[l]).
You will add the smallest to min_sum(a[i]) and if it was the right one then
increas index r, and if it was the left one then decrease index l.
Of course if the left got to 0 or the right one got to n you will most take the distaces with elemets from the other side.
Anyway you do that till you sum k elemets and that's it.
This way you didn't sort any thing but the main array.

Symmetric matrix, value into c++ vector

I am trying to solve the following problem. Let's say I have a symmetric matrix with size n. I want to take all the "important values", and store them into a vector. Let me give an example to explain it better.
Let's say I have the following matrix A = [1, 2, 3 // 2, 5, 6 // 3, 6, 9]. I want to define vector of size n*(n+1)/2 such that:
V = [A(0,0), A(0,1), A(0,2), A(1,1), A(1,2), A(2,2) ]
I want to find a function that receives as input two integer i and j, and outputs the corresponding value of the matrix. The catch is that I do not want to access the matrix directly, instead I want to access the vector.
This is my reasoning so far. If I have an input with j < i, I just swap them since the matrix is symmetric. If I have that i == 0, the position in the array is just j. If that is not the case, I think I need to do something like this. (n is the dimension of the matrix, and position is the integer that I need when for the array.)
int position = 0;
for(int k = 0; k < i; k++){
position = position + (n-k);
}
position = position + j % i;
However, this code fails. I think I'm close to the solution but I am missing something. Any help?
The last j % i should be j - i.
In addition, the loop is essentially doing
position = n + (n - 1) + ... + (n - i + 1);
which can be simplified to
position = (n * 2 - i + 1) * i / 2;
So you can simply write
position = (n * 2 - i + 1) * i / 2 + j - i;
or
position = (n * 2 - i - 1) * i / 2 + j;
You can do simply this:
int myvector[matrix.size()];
int pos = 0;
for(int i = 0; i < matrix.size(); i++){
for(int j = 0; j < matrix.size(); j++){
if(j > i) myvector[pos++] = matrix[i][j];
else myvector[pos++] = matrix[j][i];
}
}

Divide array integer 2 even sums

I am finding hard to solve this programming problem. I am required to take an array of integers that can be of size N, anywhere from 2 <= N <= 30. I need to divide the array into two smaller arrays whose sums are equal, and if they are not equal, they need to be as close as possible to the same value. I would guess that using some sort of recursive function would be ideal in this situation, but if not, a dynamically programmed solution would work just as well.
I guess you can review wikipedia article on Partition problem. It provides a pseudocode of pseudopolynomial algorithm in c# which you can rather easily convert into c++:
public static bool BalancePartition(int[] S)
{
int n = S.Length;
int N = S.Sum();
bool[,] P = new bool[N / 2 + 1, n + 1];
for (int i = 0; i < n + 1; i++)
P[0, i] = true;
for (int i = 1; i <= N / 2; i++)
for (int j = 1; j <= n; j++)
if (S[j - 1] <= i)
P[i, j] = P[i, j - 1] || P[i - S[j - 1], j - 1];
else
P[i, j] = P[i, j - 1];
return P[N / 2, n];
}

matrix blocking gives a segmentation fault

I am trying to implement the Strassen algorithm in C++. I want to partition the square matrix 'hA' into 4 equal blocks.
// Initialize matrices on the host
float hA[N][N],ha11[N / 2][N / 2], ha12[N / 2][N / 2], ha21[N / 2][N / 2],
ha22[N / 2][N / 2];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
hA[i][j] = i;
//hB[i][j] = i;
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("\n%d,%d\n", i, j);
if (i < N / 2 & j < N / 2) {
ha11[i][j] = hA[i][j];
} else if (i < N / 2 & j >= N / 2) {
ha12[i][j] = hA[i][j];
} else if (i >= N / 2 & j < N / 2) {
ha21[i][j] = hA[i][j];
} else if (i >= N / 2 & j >= N / 2) {
ha22[i][j] = hA[i][j]; //faulty!
}
}
}
I used above method for partitioning and it gets faulty as shown in the output below. But it works fine when I remove the last comparison in the 'if else' ladder.
Why does 'i' have a wrong value that is even outside the loop condition? Is there a more convenient way to do the partitioning than this way?
To work with code as written, your sub arrays need to be NxN each, not N/2 by N/2, but I dont think this is actually the "error".
You are chopping the array into 4 equal parts, so they should be able to be smaller than the original. That leaves with two issues.
Your assignments are wrong, h11 is fine, but h12, h21 and h22 all need adjusting like this:
ha12[i-N/2][j-N/2] = hA[i][j];
ha21[i-N/2][j] = hA[i][j];
ha22[i-N/2][j-N/2] = hA[i][j];
instead of what you have, (though keep them where that are).
btw, it may be easier to read if you removes the if statements altogether, iterating over just one quarter, but doing 4 assignments per quarter.
A second, potential issue is of course what happens when N isn't divisible by 2. You code seems to ignore this, which maybe it can. I expect you need to think about where you want the odd values to go, and make the sub arrays each large enough for teh rounded up parts.
Your arrays should be N x N, not N/2 x N/2.
Your use of the bitwise operator & is unusual but works. I mistakenly thought you need a logical and ( && ) instead. Still, for readability I'd suggest the &&. You get the short circuiting with too.
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("\n%d,%d\n", i, j);
if (i < N / 2 & j < N / 2) {
ha11[i][j] = hA[i][j];
} else if (i < N / 2 & j >= N / 2) {
ha12[i][j] = hA[i][j];
} else if (i >= N / 2 & j < N / 2) {
ha21[i][j] = hA[i][j];
} else if (i >= N / 2 & j >= N / 2) {
ha22[i][j] = hA[i][j]; //faulty!
}
}
}

Finding Pythagorean Triples: Euclid's Formula

I'm working on problem 9 in Project Euler:
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.
The following code I wrote uses Euclid's formula for generating primes. For some reason my code returns "0" as an answer; even though the variable values are correct for the first few loops. Since the problem is pretty easy, some parts of the code aren't perfectly optimized; I don't think that should matter. The code is as follows:
#include <iostream>
using namespace std;
int main()
{
int placeholder; //for cin at the end so console stays open
int a, b, c, m, n, k;
a = 0; b = 0; c = 0;
m = 0; n = 0; k = 0; //to prevent initialization warnings
int sum = 0;
int product = 0;
/*We will use Euclid's (or Euler's?) formula for generating primitive
*Pythagorean triples (a^2 + b^2 = c^2): For any "m" and "n",
*a = m^2 - n^2 ; b = 2mn ; c = m^2 + n^2 . We will then cycle through
*values of a scalar/constant "k", to make sure we didn't miss anything.
*/
//these following loops will increment m, n, and k,
//and see if a+b+c is 1000. If so, all loops will break.
for (int iii = 1; m < 1000; iii++)
{
m = iii;
for (int ii = 1; n < 1000; ii++)
{
n = ii;
for (int i = 1; k <=1000; i++)
{
sum = 0;
k = i;
a = (m*m - n*n)*k;
b = (2*m*n)*k;
c = (m*m + n*n)*k;
if (sum == 1000) break;
}
if (sum == 1000) break;
}
if (sum == 1000) break;
}
product = a * b * c;
cout << "The product abc of the Pythagorean triplet for which a+b+c = 1000 is:\n";
cout << product << endl;
cin >> placeholder;
return 0;
}
And also, is there a better way to break out of multiple loops without using "break", or is "break" optimal?
Here's the updated code, with only the changes:
for (m = 2; m < 1000; m++)
{
for (int n = 2; n < 1000; n++)
{
for (k = 2; (k < 1000) && (m > n); k++)
{
sum = 0;
a = (m*m - n*n)*k;
b = (2*m*n)*k;
c = (m*m + n*n)*k;
sum = a + b + c;
if ((sum == 1000) && (!(k==0))) break;
}
It still doesn't work though (now gives "1621787660" as an answer). I know, a lot of parentheses.
The new problem is that the solution occurs for k = 1, so starting your k at 2 misses the answer outright.
Instead of looping through different k values, you can just check for when the current sum divides 1000 evenly. Here's what I mean (using the discussed goto statement):
for (n = 2; n < 1000; n++)
{
for (m = n + 1; m < 1000; m++)
{
sum = 0;
a = (m*m - n*n);
b = (2*m*n);
c = (m*m + n*n);
sum = a + b + c;
if(1000 % sum == 0)
{
int k = 1000 / sum;
a *= k;
b *= k;
c *= k;
goto done;
}
}
}
done:
product = a * b * c;
I also switched around the two for loops so that you can just initialize m as being larger than n instead of checking every iteration.
Note that with this new method, the solution doesn't occur for k = 1 (just a difference in how the loops are run, this isn't a problem)
Presumably sum is supposed to be a + b + c. However, nowhere in your code do you actually do this, which is presumably your problem.
To answer the final question: Yes, you can use a goto. Breaking out of multiple nested loops is one of the rare occasions when it isn't considered harmful.