Using 4 lists, create a list of all sums - c++

I am beginner in C++ and have been trying to get an output of all the sums from 4 different lists of numbers. I want to know all the possible sums using up to 1 from each list. Repeats can be omitted.
For example with an input of [1, 2], [1, 3], [2, 3], [2, -1] should output [-1, 0, 1, 2, 3, ... 10].
My lists are 4, 6, 6, and 9 digits long, should that make a difference?
I have tried
#include<bits/stdc++.h>
using namespace std;
void subsetSums(int arr[], int l, int r,
int sum=0)
{
// Print current subset
if (l > r)
{
cout << sum << " ";
return;
}
subsetSums(arr, l+1, r, sum+arr[l]);
subsetSums(arr, l+1, r, sum);
}
int main()
{
int arr[] = {7, 14, 21, 28}, {-10, -20, -30, -40, -50, -60};
int n = sizeof(arr)/sizeof(arr[0]);
subsetSums(arr, 0, n-1);
return 0;
}
But it only produces an error:
expected unqualified-id before ‘{’ token
int arr[] = {5, 4, 3}, {4, -1, 5};

The simplest mechanism would be to create an array of all possible sums, and then remove duplicates.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<std::vector<int>> arrs = {
{7, 14, 21, 28},
{-10, -20, -30, -40, -50, -60},
{50, 90}
};
// Let's start with 0 in the results, as if we used no value from any of
// the arrays
std::vector<int> results = {0};
// Append new sums to the results list
for (const auto &arr : arrs) {
const int length = results.size();
for (int i = 0; i < length; i++)
for (int j = 0; j < arr.size(); j++)
results.push_back(results[i] + arr[j]);
}
// Remove duplicates
std::sort(results.begin(), results.end());
results.erase(
std::unique(results.begin(), results.end()),
results.end());
// Print the results
for (int value : results)
std::cout << value << " ";
std::cout << "\n";
}

Let us parse the line
int arr[] = {7, 14, 21, 28}, {-10, -20, -30, -40, -50, -60};
This is a variable definition. The type is int. The first variable being defined is arr, which due to the [] is actually an array with the size to be determined by the initialization. The = starts the initialization. The {7, 14, 21, 28} gives the four values to be stored in the array and at the same time determines that the array has four elements. The , says "I'm done defining that variable and moving on to the next variable of the same basic type". There is no name for this next variable, hence the error. The {-10, -20, -30, -40, -50, -60} would define the initial values for another array, but since you did not name another variable, the compiler gets rather confused.
One way to define two arrays is like:
int arr[] = {7, 14, 21, 28}, other_array[] = {-10, -20, -30, -40, -50, -60};
but using two lines often works out better for the human reader (the below means the same thing as the above)
int arr[] = {7, 14, 21, 28};
int other_array[] = {-10, -20, -30, -40, -50, -60};
Since you need four lists, you probably will end up with something like:
int arr1[] = {7, 14, 21, 28};
int arr2[] = {-10, -20, -30, -40, -50, -60};
int arr3[] = {-15, -25, -35, -45, -55, -65};
int arr4[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Note that you will have four lengths to keep track of. This is where std::array can become convenient.

Related

c++ get indices of duplicating rows in 2D array

The task is following: find indices of duplicating rows of 2D array. Rows considered to be duplicated if 2nd and 4th elements of one row are equal to 2nd and 4th elements of another row.The simplest way to do it is something like that:
std::unordered_set<int> result;
for (int i = 0; i < rows_count; ++i)
{
for (int j = i + 1; j < rows_count; ++j)
{
if (arr[i][2] == arr[j][2] && arr[i][4] == arr[j][4])
{
result.push_back(j);
}
}
}
But if rows_count is very large this algorithm is too slow. So my question is there any way to get needed indices using some data structures (from stl or other) with only single loop (without nested loop)?
You could take advantage of the properties of a `std::unordered_set.
A small helper class will further ease up things.
So, we can store in a class the 2nd and 4th value and use a comparision function to detect duplicates.
The std::unordered_set has, besides the data type, 2 additional template parameters.
A functor for equality and
a functor for calculating a hash function.
So we will add 2 functions to our class an make it a functor for both parameters at the same time. In the below code you will see:
std::unordered_set<Dupl, Dupl, Dupl> dupl{};
So, we use our class additionally as 2 functors.
The rest of the functionality will be done by the std::unordered_set
Please see below one of many potential solutions:
#include <vector>
#include <unordered_set>
#include <iostream>
struct Dupl {
Dupl() {}
Dupl(const size_t row, const std::vector<int>& data) : index(row), firstValue(data[2]), secondValue(data[4]){};
size_t index{};
int firstValue{};
int secondValue{};
// Hash function
std::size_t operator()(const Dupl& d) const noexcept {
return d.firstValue + (d.secondValue << 8) + (d.index << 16);
}
// Comparison
bool operator()(const Dupl& lhs, const Dupl& rhs) const {
return (lhs.firstValue == rhs.firstValue) and (lhs.secondValue == rhs.secondValue);
}
};
std::vector<std::vector<int>> data{
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, // Index 0
{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, // Index 1
{3, 4, 42, 6, 42, 8, 9, 10, 11, 12}, // Index 2 ***
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, // Index 3
{5, 6, 42, 8, 42, 10, 11, 12, 13, 14}, // Index 4 ***
{6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, // Index 5
{7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, // Index 6
{8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, // Index 7
{9, 10, 42, 12, 42, 14, 15, 16, 17, 18}, // Index 8 ***
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, // Index 9
};
int main() {
std::unordered_set<Dupl, Dupl, Dupl> dupl{};
// Find the unique rows
for (size_t i{}; i < data.size(); ++i)
dupl.insert({i, data[i]});
// Show some debug output
for (const Dupl& d : dupl) {
std::cout << "\nIndex:\t " << d.index << "\t\tData: ";
for (const int i : data[d.index]) std::cout << i << ' ';
}
}

Searching for overlapping integers in different indexes of tuples in a vector

I was wondering how one can search for overlaps in a vector of tuples.
For example, I have the vector<tuple<int, int, int>> combo;, and the elements of the vector is:
{10, 101, 1},
{10, 102, 2},
{12, 102, 3},
{14, 90, 4},
{1, 10, 101},
{2, 10, 102},
{3, 12, 102},
{4, 14, 90},
{101, 1, 10},
{102, 2, 10},
{102, 3, 12},
{90, 4, 14}
Here, you can tell that the bottom 8 tuples are just repeats of the first 4, except the integers are reordered in a different way. I want to find the non-overlapping combinations of the elements, not the permutations of the elements.
If the 1st index of the tuple is called left, second if called middle, and third is called right, then in other words, left, middle, and right can overlap with itself, but not with the other 2 indexes.
Convert the elements to a canonical representation. This allows you use a set data structure or similar to identify duplicates.
I'm assuming here you're trying to find permutations that do not result in one of the elements remaining in place, i.e. for values { a, b, c} the matching permutations would be
{ a, b, c }
{ b, c, a }
{ c, a, b }
Furthermore I'm assuming even if multiple values are the same, they could be considered as listed in any order, i.e. { 1, 1, 2 } would match { 1, 2, 1 } even though the first element remains equal, since we could consider the first element to be the second one in the original.
This allows us use the lexicographically minimal alternative that as the canonical representation.
The following code uses std::array<int, 3> for convenience.
#include <array>
#include <iostream>
#include <map>
#include <vector>
using ValueType = std::array<int, 3>;
constexpr ValueType ToCanonical(ValueType const& original)
{
ValueType p1{ original[1], original[2], original[0] };
ValueType p2 { original[2], original[0], original[1] };
return (std::min)({ original, p1, p2 });
}
int main(void) {
std::vector<ValueType> const values
{
{10, 101, 1},
{10, 102, 2},
{12, 102, 3},
{14, 90, 4},
{1, 10, 101},
{2, 10, 102},
{3, 12, 102},
{4, 14, 90},
{101, 1, 10},
{102, 2, 10},
{102, 3, 12},
//{90, 4, 14},
//{10, 101, 1},
//{101, 10, 1},
//{10, 1, 101},
//{1, 101, 10},
//{1, 1, 2},
//{1, 2, 1},
//{2, 1, 1},
};
std::map<ValueType, size_t> indices;
for (size_t i = 0; i != values.size(); ++i)
{
auto insertResult = indices.try_emplace(ToCanonical(values[i]), i);
if (!insertResult.second)
{
std::cout << "The element at index " << i << " is a duplicate of the element at index " << insertResult.first->second << '\n';
}
}
return 0;
}

Issue with passing an argument to function

I'm working with C++ and found a problem. I want to pass an argument to a function. The argument must be a 2d array. When I try to do it, I get 2 errors:
Too many initializer values
and
initializing cannnot convert from initializer list to size_t**
How do I fix this? I've tried with changing it as 5x5 matrix, but it doesn't make it good.
size_t** matrix =
{
{1, 16, 20, 23, 25},
{6, 2, 17, 21, 24},
{10, 7, 3, 18, 22},
{13, 11, 8, 4, 19},
{15, 14, 12, 9, 5},
};
set<bool> set1 = iterateover(matrix);
The function:
std::set<bool> iterateover(size_t **arrayy)
size_t** matrix defines a pointer to a pointer to a size_t. An array is not a pointer. It can decay to a pointer, but in the case of a 2D array, it decays to a pointer to a 1D array, not to a pointer to a pointer.
The closest thing I can think of to what you seem to be after is
// here be the data
size_t actual_matrix[][5] = // note: We can omit the first dimension but we cannot
// omit the inner dimensions
{
{1, 16, 20, 23, 25},
{6, 2, 17, 21, 24},
{10, 7, 3, 18, 22},
{13, 11, 8, 4, 19},
{15, 14, 12, 9, 5},
};
// an array of pointers to the rows of actual data. This 1D array of pointers will
// decay to a size_t **
size_t * matrix[] =
{
actual_matrix[0],
actual_matrix[1],
actual_matrix[2],
actual_matrix[3],
actual_matrix[4],
};
// now we have the correct type to use with iterateover
std::set<bool> set1 = iterateover(matrix);
I want to pass an argument to a function. The argument must be a 2d array.
You can make iteratreOver a function template which can take a 2D array by reference, as shown below. You can make additional changes to the function according to your needs since it is not clear from the question what your iterateover function does. I have just printed all the elements inside the 2D array.
#include <iostream>
template<typename T,std::size_t N, std::size_t M>
void iterateOver(T (&arr)[N][M])
{
for(std::size_t i= 0; i < N; ++i)
{
for(std::size_t j = 0; j < M; ++j)
{
std::cout<<arr[i][j] <<" ";
}
std::cout<<std::endl;
}
}
int main()
{
size_t matrix[5][5] =
{
{1, 16, 20, 23, 25},
{6, 2, 17, 21, 24},
{10, 7, 3, 18, 22},
{13, 11, 8, 4, 19},
{15, 14, 12, 9, 5},
};
//call iterateOver by passing the matrix by reference
iterateOver(matrix);
}
The output of the above program can be seen here:
1 16 20 23 25
6 2 17 21 24
10 7 3 18 22
13 11 8 4 19
15 14 12 9 5

Algorithm for max number of pairs with two limits

I guess that such an algorithm already exists.
I have two (or more, but two is sufficient for this problem) limits, e.g. limit_a=20 limit_b=18. Then I have some (a, b) pairs, e.g.
(5, 5), (3, 3), (4, 2), (1, 7), (3, 2), (5, 9), (7, 4)
The answer should be 5. An example of a solution: (7, 4), (3, 2), (1, 7), (4, 2), (3, 3)
I need to choose as many pairs as possible such that the sum of all "a" elements is less or equal to limit_a and analogously with "b". I thought that it is 2D Knapsack problem, but it isn't.
My best "solution" is to check all permutations of the list of these pairs and check the sums. It's fine for example, like above one, but of course not with bigger one's. My C++ code:
#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
using namespace std;
int main()
{
int limit_a = 20;
int limit_b = 18;
vector<pair<int, int>> vect;
vect.push_back(make_pair(5, 5));
vect.push_back(make_pair(3, 3));
vect.push_back(make_pair(4, 2));
vect.push_back(make_pair(1, 7));
vect.push_back(make_pair(3, 2));
vect.push_back(make_pair(5, 9));
vect.push_back(make_pair(7, 4));
int how_many_max = 0;
do {
int copy_a = limit_a;
int copy_b = limit_b;
int how_many = 0;
for ( vector<pair<int,int>>::const_iterator it = vect.begin(); it != vect.end(); it++){
copy_a -= it->first;
copy_b -= it->second;
if((copy_a < 0) || (copy_b < 0)) {
break;
}
how_many++;
}
if (how_many > how_many_max) how_many_max = how_many;
} while(next_permutation(vect.begin(), vect.end() ));
cout << how_many_max;
return 0;
}
Example:
int limit_a = 30;
int limit_b = 80;
std::vector<std::pair<int, int>> vect = {{37, 20}, {90, 45}, {76, 33}, {3, 93}, {66, 71}, {48, 21}, {8, 28}, {24, 83}, {99, 13}, {42, 52}, {81, 15}, {2, 38}, {7, 19}, {32, 65}, {70, 85}, {12, 82}, {61, 6}, {60, 31}, {46, 34}, {43, 62}, {41, 78}, {64, 80}, {88, 86}, {77, 16}, {44, 100}, {92, 57}, {40, 53}, {9, 56}, {68, 67}, {23, 11}, {35, 30}, {69, 84}, {75, 27}, {87, 26}, {50, 36}, {79, 73}, {4, 91}, {17, 98}, {51, 29}, {25, 95}, {14, 55}, {10, 58}, {54, 49}, {97, 63}, {59, 72}, {1, 39}, {18, 22}, {94, 74}, {96, 5}, {47, 89}
Should give 3: ({2, 38}, {7, 19}, {18, 22})
It is a 2D knapsack problem, just the profits are all 1. The usual approach of generating subsets interleaved with pruning where a partial subsolution obviously dominates another applies.
Some quick code below, using sorting instead of a merge for convenience.
#include <algorithm>
#include <iostream>
#include <tuple>
#include <utility>
#include <vector>
int main() {
int limit_a = 20;
int limit_b = 18;
std::vector<std::pair<int, int>> vect = {{5, 5}, {3, 3}, {4, 2}, {1, 7},
{3, 2}, {5, 9}, {7, 4}};
limit_a = 30;
limit_b = 80;
vect = {{37, 20}, {90, 45}, {76, 33}, {3, 93}, {66, 71}, {48, 21}, {8, 28},
{24, 83}, {99, 13}, {42, 52}, {81, 15}, {2, 38}, {7, 19}, {32, 65},
{70, 85}, {12, 82}, {61, 6}, {60, 31}, {46, 34}, {43, 62}, {41, 78},
{64, 80}, {88, 86}, {77, 16}, {44, 100}, {92, 57}, {40, 53}, {9, 56},
{68, 67}, {23, 11}, {35, 30}, {69, 84}, {75, 27}, {87, 26}, {50, 36},
{79, 73}, {4, 91}, {17, 98}, {51, 29}, {25, 95}, {14, 55}, {10, 58},
{54, 49}, {97, 63}, {59, 72}, {1, 39}, {18, 22}, {94, 74}, {96, 5},
{47, 89}};
std::vector<std::vector<std::pair<int, int>>> frontier = {
{{limit_a, limit_b}}};
for (auto [a, b] : vect) {
frontier.push_back({});
for (std::size_t how_many = frontier.size() - 1; how_many > 0; how_many--) {
std::vector<std::pair<int, int>> &level = frontier[how_many];
for (auto [residual_a, residual_b] : frontier[how_many - 1]) {
if (residual_a >= a && residual_b >= b)
level.push_back({residual_a - a, residual_b - b});
}
if (level.empty())
continue;
std::sort(level.begin(), level.end(),
std::greater<std::pair<int, int>>());
auto output = level.begin();
auto input = output;
for (++input; input != level.end(); ++input) {
if (std::tie(input->second, input->first) >
std::tie(output->second, output->first))
*++output = *input;
}
level.erase(++output, level.end());
if ((false)) {
for (auto [residual_a, residual_b] : level) {
std::cout << residual_a << ',' << residual_b << ' ';
}
std::cout << '\n';
}
}
}
std::size_t how_many_max = frontier.size() - 1;
while (frontier[how_many_max].empty())
how_many_max--;
std::cout << how_many_max << '\n';
}
In higher dimensions, the pruning gets more complicated. The curse of dimensionality also kicks in because domination relation gets sparser. Integer programming might be a better solution here.
A naive search space for bottom-up dynamic programming seems to be O(n * limit_a * limit_b) but this can get a lot more idiosyncratic, depending on the input, so we could possibly favour a memoised recursion.
function f(pairs, a, b, i=0, memo={}){
if (i == pairs.length)
return 0;
const key = String([i, a, b]);
if (memo.hasOwnProperty(key))
return memo[key];
// Skip this pair
let best = f(pairs, a, b, i+1, memo);
const [l, r] = pairs[i];
// Maybe include this pair
if (l <= a && r <= b)
best = Math.max(best, 1 + f(pairs, a-l, b-r, i+1, memo));
return memo[key] = best;
}
var pairs = [
[5, 5], [3, 3], [4, 2],
[1, 7], [3, 2], [5, 9], [7, 4]
];
console.log(f(pairs, 20, 18));

In C and C++, how to move some elements in an array into a new array?

For example, how can I move the 1st, 5th and 10th elements in array A to a new three-elements array B without assigning separately for three times?
In C, just declare and initialize a new array with the selected elements of your array. No assignment needed.
int main(void)
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[3] = {a[0], a[4], a[9]};
return 0;
}
Remember that initializers for arrays with automatic storage duration does not have to be constants.
Just do the three assignments! Why do you avoid it?
int ar1[10], ar2[10];
ar2[0] = ar1[0];
ar2[4] = ar1[4];
ar2[9] = ar1[9];
However, if you have lots of indices to move, perhaps you need another way.
I suggest this:
int ar1[1000], ar2[1000];
int indices[] = { 1, 3, 54, 6, 23, 35, 9, 42, 44, 995, 722, .... };
for (int i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
{
ar2[i] = ar1[i];
}