set constructor with custom compare function - c++

How is the y.size() = 4 in the following? The values in y are {11, 2, 4, 7} How does one arrive at this? What are a and b in the operator() function for each iteration of the set. I don't understand the construction of y and I can't find anything online that explains this situation. Thank You
#include <iostream>
#include <set>
struct C
{
bool operator()(const int &a, const int &b) const
{
return a % 10 < b % 10;
}
};
int main()
{
std::set<int> x({ 4, 2, 7, 11, 12, 14, 17, 2 });
std::cout << x.size() << std::endl;
std::set<int, C> y(x.begin(), x.end());
std::cout << y.size() << std::endl;
std::set<int>::iterator iter;
for (iter = y.begin(); iter != y.end(); ++iter)
{
std::cout << *iter << std::endl;
}
return 0;
}

Second template argument of set is comparator type — type of functor that implements less operation.
struct C
{
bool operator()(const int &a, const int &b) const
{
return a % 10 < b % 10;
}
};
This comparator will compare a and b as a < b only if a % 10 < b % 10, so practically all numbers will be compared by modulo 10.
UPDATE:
After pushing into x set numbers { 4, 2, 7, 11, 12, 14, 17, 2 }, set will contain seven elements { 2, 4, 7, 11, 12, 14, 17 }. These elements will be sorted in that way, because set stores objects in sorted way.
Then numbers from x set are being sequentially inserted into y set. Before inserting of each element, set will find proper place in sorted order of currently inserted numbers. If set will see, that there is already some number on it's place, set will not insert it.
After inserting {2, 4, 7} from x to y, y will be {2, 4, 7}.
Then, to insert 11 into y set will do comparisons of 11 with {2, 4, 7} to find proper place using provided C functor.
To check is 11 less than 2 set will call C()(11, 2), which will result in 11 % 10 < 2 % 10 comparison, which will result in true, so 11 will be inserted before 2.
Other numbers from x (12, 14, 17) will not be inserted, because set will find, that 12 should be on place of 2 (because 2 % 10 < 12 % 10 or 12 % 10 < 2 % 10 expression is false, so 2 == 12), and in same way 14 and 17.

Related

How can I sort only some parts of the array in a specific order in c++?

So let's assume I have an array array{12, 10, 10, 9, 8, 8, 8} in descending order.
I want to sort the numbers that can be divided by 2 but not with 4 in ascending order at the end of the array, the numbers that are divided by 4 sorted at the start of the array in descending order and the rest in the middle(no specific order). For my example, after the transformation it should look something like this:
array{12, 8, 8, 8, 9, 10, 10}. Is there any way I can do this efficiently? c++ language.
Sorry for any misspelling.
Let's organize the requirement.
The required order is:
Numbers that are divided by 4
Others
Numbers that can be divided by 2 but not with 4
Among the numbers with same priority according to the above rule, the numbers should be
Descending order
No specific order
Ascending order
Let's implement this:
#include <iostream>
#include <vector>
#include <algorithm>
void test(std::vector<int> array) { // intensionally passed by value
std::cout << "before sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
std::sort(array.begin(), array.end(), [](int a, int b) -> bool {
int pa, pb; // priority a/b
if (a % 4 == 0) pa = 1;
else if (a % 2 == 0) pa = 3;
else pa = 2;
if (b % 4 == 0) pb = 1;
else if (b % 2 == 0) pb = 3;
else pb = 2;
// if the priority differs, sort according to the priority
if (pa != pb) return pa < pb;
// if both can be divided by 4, sort in descending order
if (pa == 1) return b < a;
// if both can be divided by 2 but not with 4, sort in ascending order
if (pa == 3) return a < b;
// no specific order for the rest
return false;
});
std::cout << "after sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
}
int main(void) {
std::vector<int> array = {12, 10, 10, 9, 8, 8, 8};
std::vector<int> array2 = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
test(array);
std::cout << '\n';
test(array2);
return 0;
}
Example output:
before sorting: 12 10 10 9 8 8 8
after sorting: 12 8 8 8 9 10 10
before sorting: 10 9 8 7 6 5 4 3 2 1
after sorting: 8 4 9 7 5 3 1 2 6 10
As an alternative to MikeCAT's fine answer, C++20 adds a variation of sort which accepts a projection, i.e. a function to apply to each element before we pass it to the comparison functor.
This utilises the fact that std::tuple has a predefined < that orders the tuple by each member in turn.
#include <iostream>
#include <vector>
#include <algorithm>
std::tuple<int, int> my_order(int val) {
if (val % 4 == 0) return { 1, -val };
else if (val % 2 == 0) return { 3, val };
else return { 2, 0 };
}
void test(std::vector<int> array) { // intensionally passed by value
std::cout << "before sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
std::ranges::sort(array.begin(), array.end(), std::ranges::less{}, my_order);
std::cout << "after sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
}
int main(void) {
std::vector<int> array = {12, 10, 10, 9, 8, 8, 8};
std::vector<int> array2 = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
test(array);
std::cout << '\n';
test(array2);
return 0;
}

Efficient way to compute unique permutations with restrictions

so I know that there are a lot of ways to compute unique permutations.
Usually it is slower to apply restrictions during the generation than removing them afterwards.
So let's say I have a vector of 10 elements.
For the sake of an example:
std::vector<int> v = {7, 5, 16, 8, 5, 8, 1, 7, 3, 25, 109, 8};
I have the unique restriction that I know that I am not allowed to have the same three numbers in a row, so all permutations containing {8,8,8} in any place would be invalid.
In case I have a giant array of e.g. 20 elements I would assume that I could save a lot of time if I skip all permutations that start with {8,8,8}.
Is there any to do anything like this efficiently? How do I figure out at which point it makes sense to add the additional slowdown of checking each permutation?
With your restriction, while iterating in order, it is possible to skip the block of invalid permutations, from the first invalid one.
The first invalid permutation from number of the form
y y y 8 8 x x 8 x
is
y y y 8 8 8 x1 x2 x3 with x1 < x2 < x3.
so you can go directly to last invalid permutation with
y y y 8 8 8 x3 x2 x1 with x1 < x2 < x3.
so just reverse the last numbers.
bool is_valid(const std::vector<int>& v)
{
auto it = std::find(v.begin(), v.end(), 8);
return v.end() - it >= 3 && (*it != *(it + 1) || *it != *(it + 2));
}
void go_to_last_invalid(std::vector<int>& v)
{
auto it = std::find(v.begin(), v.end(), 8);
std::reverse(it + 3, v.end());
}
int main()
{
std::vector<int> v = {1, 7, 7, 8, 8, 8, 9, 10};
do {
if (!is_valid(v)) { go_to_last_invalid(v); continue; }
for (auto e : v) { std::cout << e << " "; } std::cout << std::endl;
} while (std::next_permutation(v.begin(), v.end()));
}
Demo

Product modulo random numbers

A prime p is fixed. A sequence of n numbers is given, each from 1 to p - 1. It is known that the numbers in the sequence are chosen randomly, equally likely and independently from each other. Choose some numbers from the sequence so that their product, taken modulo p, is equal to the given number x. If no numbers are selected, the product is considered equal to one.
Input:
The first line contains three integers separated by spaces: the length of the sequence n, the prime number p and the desired value x
(n=100, 2<=p<=10^9, 0<x<p)
Next, n integers are written, separated by spaces or line breaks: the sequence a1, a2,. . ., an
(0 <ai <p)
Output:
Print the numbers from the sequence whose product modulo p is equal to x. The order in which numbers are displayed is not important. If there are several possible answers, print any of them
Example:
INPUT:
100 11 4
9 6 1 1 10 4 9 10 3 1 10 1 6 8 3 3 9 8
10 3 7 7 1 3 3 1 5 2 10 4 1 5 6 7 2 6
2 8 3 3 6 7 6 3 1 5 10 2 2 10 9 6 8 6
2 10 3 2 7 4 3 2 8 6 4 1 7 2 10 8 4 9
7 9 8 7 4 7 3 2 8 2 3 7 1 5 2 10 7 1 8
6 4 10 10 3 6 10 2 1
OUTPUT:
4 6 10 9
My solution:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n,p,x,y,m,k,tmp;
vector<int> v;
cin >> n >> p >> x;
for (int i = 0; i<n; i++){
cin >> tmp;
v.push_back(tmp);
}
sort(v.begin(), v.end());
v.erase(v.begin(), upper_bound(v.begin(), v.end(), 1));
k=-1;
while(1){
k++;
m = 1;
y = x+p*k;;
vector<int> res;
for (int i = 0; i<n; i++){
if (y == 1) break;
if ( y%v[i] == 0){
res.push_back(v[i]);
m*=v[i];
m%=p;
y = y/v[i];
}
}
if (m==x) {
for (int i = 0; i<res.size(); i++){
cout << res[i] << " ";
}
break;
}
}
return 0;
}
In my solution, I used condition (y=x+k*p, where y is the product of numbers in the answer, and k is some kind of natural number). And also iterated over the value k.
This solution sometimes goes beyond the allotted time. Please tell me a more correct algorithm.
I would consider a backtracking routine over the hashed multiset of the input list. Since p is a prime, at any point we can consider if the current multiple, m, has (multiplicative_inverse(m, p) * x) % p in our multiset (https://en.wikipedia.org/wiki/Multiplicative_inverse). If it exists, we're done. Otherwise, try multiplying either by the same number we are currently visiting in the multiset, or by the next one (keep the result of the multiplication modulo p).
Please see comment below for a link to example code in Python. The example you gave has trivial solutions so it would be helpful to have some non-trivial, as well as challenging examples to test and refine on. Please also clarify if more than one number is expected in the output.
You can use dynamic programming approach. It requires O(p) memory cells and O(p*n) loop iterations. There is possible several optimization (to exclude processing input duplicates, or print longest/shortest selection chain). Following is simplest and basic DP-program, demonstrating this approach.
#include <stdio.h>
#include <stdlib.h>
int data[] = {
9, 6, 1, 1, 10, 4, 9, 10, 3, 1, 10, 1, 6, 8, 3, 3, 9, 8,
10, 3, 7, 7, 1, 3, 3, 1, 5, 2, 10, 4, 1, 5, 6, 7, 2, 6,
2, 8, 3, 3, 6, 7, 6, 3, 1, 5, 10, 2, 2, 10, 9, 6, 8, 6,
2, 10, 3, 2, 7, 4, 3, 2, 8, 6, 4, 1, 7, 2, 10, 8, 4, 9,
7, 9, 8, 7, 4, 7, 3, 2, 8, 2, 3, 7, 1, 5, 2, 10, 7, 1, 8,
6, 4, 10, 10, 3, 6, 10, 2, 1
};
struct elm {
int val; // Value
int prev; // from which elemet we come to this
int n; // add loop cound for prevent multiple use same val
};
void printsol(int n, int p, int x, const int *in) {
struct elm *dp = (struct elm *)calloc(p, sizeof(struct elm));
int i, j;
for(i = 0; i < n; i++) // add initial elements into DP array
dp[in[i]].val = in[i];
for(i = 0; i < n; i++) { // add elements, one by one, to DP array
if(dp[in[i]].val <= 1) // skip secondary "1" multipliers
continue;
for(j = 1; j < p; j++)
if(dp[j].val != 0 && dp[j].n < i) {
int y = ((long)j * in[i]) % p;
dp[y].val = in[i]; // current value, for printout
dp[y].prev = j; // reference to prev element
dp[y].n = n; // loop num, for prevent double reuse
if(x == y && dp[x].n > 0) {
// targed reached - print result, by iterate linklist
int mul = 1;
while(x != 0) {
printf(" %d ", dp[x].val);
mul *= dp[x].val; mul %= p;
x = dp[x].prev;
}
printf("; mul=%d\n", mul);
free(dp);
return;
}
} // for+if
} // for i
free(dp);
}
int main(int argc, char **argv) {
printsol(100, 11, 4, data);
return 0;
}

C++: std::map, find cycles, algorithm

Suppose the following data structure:
std::map <int, std::vector<int> > M,
where val is represented by the sequence of vertices of the graph, and the key is the first vertex of the sequence. For example
{1} {1, 8, 12, 7}
{4} {4, 3, 5}
{7} {7, 9, 13, 18, 0, 2}
{2} {2, 11, 1}
{5} {5, 17, 10, 4}
{9} {9, 6, 19, 14}
{14} {14, 15, 9}
How to find all cycles (analogous start and end vertex) from the segments {}
C1: {1 8 12 7} {7 9 13 18 0 2} {2 11 1}
C2: {4 3 5} {5 17 10 4}
C3: {9 6 19 14} {14, 15, 9}
and how to avoid the duplicate sequence of segments, with the low time complexity (map may contain hundreds of thousands of sequences). Any cycle may contain n segments {}, where n>=1.
The initialization phase:
std::map <int, std::vector <int> > M;
M[1] = std::vector<int>{ 1, 8, 12, 7 };
M[4] = std::vector<int>{ 4, 3, 5 };
M[7] = std::vector<int>{ 7, 9, 13, 18, 0, 2 };
M[2] = std::vector<int>{ 2, 11, 1 };
M[5] = std::vector<int>{ 5, 17, 10, 4 };
M[9] = std::vector<int>{ 9, 6, 19, 14 };
M[14] = std::vector<int>{ 14, 15, 9 };
The draft of the algorithm:
std::vector<std::vector <int> > R;
for (auto im = M.begin(); im != M.end();)
{
std::vector<int> r, ri = im->second;
for(;;)
{
r.insert(r.end(), ri.begin(), ri.end());
ri = M[r.back()];
im = M.erase(M.find(im->first));
if (r.back() == r.front()) break;
}
R.push_back(r);
}
Unfortunately, the repeated deletion represents an expensive operation... I hope, there is a more beautiful and efficient solution :-)
Thanks for your help...
First, your inner loop needs to be a function (what if the paths don't cycle?)
Then, declare failure if either
The end node is numerically less than the start node (could be a cycle, but is not a canonical, so we won't print this shifted version)
The end node isn't found in the master table of paths
And that leads to a solution:
bool try_follow(int from, std::vector<int>& result)
{
int current = from;
while (true) {
auto path = M.find(current);
if (path == M.end()) return false;
current = path->second.back();
if (current < from) return false;
result.insert(result.end(), path->second.begin()+1, path->second.end());
if (current == from) return true;
}
}
int main(void)
{
for( auto& kvp : M )
{
std::vector<int> x;
if (try_follow(kvp.first, x)) {
std::cout << kvp.first;
for( int y : x )
std::cout << " - " << y;
std::cout << std::endl;
}
}
}
Demo: https://rextester.com/DWWZ9457
My first crack:
for (auto it : M)
{
if (it.first < it.second.back() && it.second.front() == M[it.second.back()].back())
std::cout << "Cycle between " << it.first << " and " << it.second.back() << '\n';
}
Won't find cycles that involve 3+ paths, of course.

Sorting doesn't seem to work

This code is written in C++. I've the following structure:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
struct Data
{
int h, b, w;
Data(int _h, int _b, int _w) : h(_h), b(_b), w(_w)
{}
bool operator<(const Data& other) const
{
bool overlap = (other.b >= b && other.b <= w) ||
(other.w >= b && other.w <= w) ||
(other.b < b && other.w > w);
if (overlap)
{
return h < other.h;
}
return h > other.h;
}
};
The operator< will be used for sorting. The idea is to sort from highest-h to lowest-h, unless there is any overlapping between either b or w in comparing variables. Remaining code:
vector <int> getOrdering(vector <int> height, vector <int> bloom, vector <int> wilt)
{
vector<Data> vdata;
for (int i = 0; i < height.size(); i++)
{
vdata.push_back(Data(height[i], bloom[i], wilt[i]));
}
sort(vdata.begin(), vdata.end());
vector<int> ans;
for (Data data : vdata)
{
ans.push_back(data.h);
}
return ans;
}
int main()
{
vector <int> p0 = { 1, 2, 3, 4, 5, 6 };
vector <int> p1 = { 1, 3, 1, 3, 1, 3 };
vector <int> p2 = { 2, 4, 2, 4, 2, 4 };
vector<int> ans = getOrdering(p0, p1, p2);
for (int a : ans)
{
cout << a << ' ';
}
cout << endl;
return 0;
}
The way the I've written the operator< function, the code should output 2 4 6 1 3 5. But the output is 6 5 4 3 2 1. I'm using Visual Studio 2013 Ultimate.
After debugging the operator< function, I found out that it is being called for Data object as follows:
1st call: this->h = 2, other.h = 1
2nd call: this->h = 1, other.h = 2
3rd call: this->h = 3, other.h = 2
4th call: this->h = 2, other.h = 3
5th call: this->h = 4, other.h = 3
6th call: this->h = 3, other.h = 4
7th call: this->h = 5, other.h = 4
8th call: this->h = 4, other.h = 5
9th call: this->h = 6, other.h = 5
10th call: this->h = 5, other.h = 6
Note that when Data objects' h values are 1, 3 or 5, their b and w values are same. They will be sorted by ascending order of h. Same goes true for Data objects whose h values are 2, 4 and 6. But in the operator<() no two Data objects are ever compared whose h values are same! 1 compared to 2, 2 compared to 3, 3 compared to 4 and so on. So the overlap variable is always false. The outcome of sort() would be different if Data objects whose h values are same got compared - but that never happened!
Any explanation of this behavior of compiler?
It is because your operator< depends a lot of the data order. If we run you're algorithm with your data, it's the expected output.
The first comparaison is between Data(1,1,2) and Data(2,3,4). According to your operator<, Data(2,3,4) is the lower so the temp order is [Data(2,3,4), Data(1,1,2)]
Then, Data(3,1,2) comes and is compared against the lowest value of the current sorted list, so Data(2,3,4). Again, according to your operator<, Data(3,1,2) is lower so no need to compare against the other values in the list and the new temp ordered list is [Data(3,1,2),Data(2,3,4), Data(1,1,2)].
Then it's the same for each other value, they are each time only compared to the first value in the list since they are lower (according to operator<) and so put in front of the sorted list.
If you change your init list order with:
vector <int> p0 = { 6, 5, 4, 3, 2, 1};
vector <int> p1 = { 3, 1, 3, 1, 3, 1};
vector <int> p2 = { 4, 2, 4, 2, 4, 2};
you'll have the expected output since there will be more comparaison involved.
But the fact that the result depend on the init order show there is clearly a flaw in your operator< function.