Algorithm for max number of pairs with two limits - c++

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

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

Path between two points inside a Boost Geometry polygon

I'm trying to find the "path" to connect two points in a c++ boost polygon.
I have a polygon like that
namespace bgm = bg::model;
using Point = bgm::d2::point_xy<double>;
bgm::polygon<Point> poly;
bg::read_wkt("POLYGON((" + points_poly + "))", poly);
And i have randoms points in the polygon.
And i would like to know if boost c++ have tools to help in a case like that.
It's pretty unclear what the actual question is, so here's what asnwers directly to your question:
Poly poly{{
{-4, 14}, {17.75, 13.99}, {17.75, 7.95}, {10, 8}, {10, 2},
{16, 2}, {16, -8}, {22, -8}, {13.97, -13.17}, {6, -8},
{12, -8}, {12, -2}, {-0.99, -2.06}, {-0.9, -7.95}, {-18, -8},
{-18, 2}, {-10, 2}, {-10, 6}, {-6, 6}, {-6, 2},
{-2, 8}, {-7.05, 8}, {-7.15, 14}, {-4, 14},
}};
Point A{-7.08, 10.07};
Point B{10, 4};
LineString path{A, {4, 10}, {4, 4}, B};
The WKT for those is:
poly: POLYGON((-4 14,17.75 13.99,17.75 7.95,10 8,10 2,16 2,16 -8,22 -8,13.97
-13.17,6 -8,12 -8,12 -2,-0.99 -2.06,-0.9 -7.95,-18 -8,-18 2,-10 2,-10 6,-6 6,
-6 2,-2 8,-7.05 8,-7.15 14,-4 14))
A: POINT(-7.08 10.07)
B: POINT(10 4)
path: LINESTRING(-7.08 10.07,4 10,4 4,10 4)
Turning it into a SVG image:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using Point = bgm::d2::point_xy<double>;
using Poly = bgm::polygon<Point>;
using LineString = bgm::linestring<Point>;
int main() {
Poly poly{{
{-4, 14}, {17.75, 13.99}, {17.75, 7.95}, {10, 8}, {10, 2},
{16, 2}, {16, -8}, {22, -8}, {13.97, -13.17}, {6, -8},
{12, -8}, {12, -2}, {-0.99, -2.06}, {-0.9, -7.95}, {-18, -8},
{-18, 2}, {-10, 2}, {-10, 6}, {-6, 6}, {-6, 2},
{-2, 8}, {-7.05, 8}, {-7.15, 14}, {-4, 14},
}};
Point A{-7.08, 10.07};
Point B{10, 4};
LineString path{A, {4, 10}, {4, 4}, B};
std::cout << "poly: " << bg::wkt(poly) << "\n";
std::cout << "A: " << bg::wkt(A) << "\n";
std::cout << "B: " << bg::wkt(B) << "\n";
std::cout << "path: " << bg::wkt(path) << "\n";
{
std::ofstream svg("output.svg");
boost::geometry::svg_mapper<Point> mapper(svg, 400, 400);
mapper.add(poly);
mapper.add(path);
mapper.add(A);
mapper.add(B);
mapper.map(poly, "fill-opacity:0.3;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(path, "fill-opacity:0.05;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(A, "fill:red;stroke-width:20");
mapper.map(B, "fill:red;stroke-width:20");
mapper.text(A, "A", "");
mapper.text(B, "B", "");
}
}
Printing the WKT (see above) as well as writing output.svg:

shift cyclically second row in 2D array c++ 98

Hi guys i was looking around some old threads but i can't find anything that works for me. I need to shift second row in my array with cpp 98 from this
int mat[4][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}};
to this
int mat[4][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{12, 9 , 10, 11},
{13, 14, 15, 16}};
I don't want to print out anything just switching places in array, Thank you
One very easy method is this, first create a temporary array to store the initial values,
int temp[4] = { mat[2][3], mat[2][0], mat[2][1], mat[2][2] };
Then use std::memcpy to copy the data into mat[2],
std::memcpy(mat[2], temp, sizeof(int) * 4);
Bonus: You can use a scope to save some memory. It would be like this,
int mat[4][4] = { {1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16} };
...
{
int temp[4] = { mat[2][3], mat[2][0], mat[2][1], mat[2][2] };
std::memcpy(mat[2], temp, sizeof(int) * 4);
}

Using 4 lists, create a list of all sums

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.