Efficient way to enumerate unique undirected paths - c++

Given a subset of nodes {1,2,...,N} is there any STL or boost function that returns unique undirected tours over all of them?
std::next_permutation() gives all N! directed tours, where 1-2-...-N is different from N-N-1-...-2-1.
However, in this case, I don't want both of them, but only one of them. Essentially, I would like to enumerate only N! / 2 of the tours.
The following code that uses std::next_permutation() and unordered_set works, but is there anything more efficient? The following code essentially generates all N! directed tours and discards half of them after checking against an unordered_set().
#include <vector>
#include <unordered_set>
#include <algorithm>
#include <boost/functional/hash.hpp>
template <typename T, typename U> bool unorderedset_val_there_already_add_if_not(std::unordered_set<T, U>& uos, T& val) {
if (uos.find(val) != uos.end())
return true;//val already there
uos.insert(val);
return false;//Value is new.
}
int main() {
std::vector<int> sequence{ 1, 2, 3};
std::unordered_set<std::vector<int>, boost::hash<std::vector<int>>> uos;
do {
printf("Considering ");
for (std::size_t i = 0; i < sequence.size(); i++)
printf("%d ", sequence[i]);
printf("\n");
std::vector<int> rev_sequence = sequence;
std::reverse(rev_sequence.begin(), rev_sequence.end());
if (unorderedset_val_there_already_add_if_not(uos, sequence) || unorderedset_val_there_already_add_if_not(uos, rev_sequence)) {
printf("Already there by itself or its reverse.\n");
}
else {
printf("Sequence and its reverse are new.\n");
}
} while (std::next_permutation(sequence.begin(), sequence.end()));
getchar();
}
That is, given {1,2,3}, I only want to enumerate (1-2-3), (1-3-2) and (2-1-3). The other three permutations (2-3-1), (3-1-2) and (3-2-1) should not be enumerated because their reverse sequence have already been enumerated.

If you want to stay with next_permutation rather than make own generator routine, the simplest way is filter out a half of permutation with some condition.
Very simple one: the last element should be larger than the first one.
#include <vector>
#include <algorithm>
#include "stdio.h"
int main() {
std::vector<int> sequence{ 1, 2, 3, 4};
do {
if (sequence[sequence.size()-1] > sequence[0]) {
for (std::size_t i = 0; i < sequence.size(); i++)
printf("%d ", sequence[i]);
printf("\n");
}
} while (std::next_permutation(sequence.begin(), sequence.end()));
getchar();
}
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 3 4
2 1 4 3
2 3 1 4
2 4 1 3
3 1 2 4
3 2 1 4
Possible own implementation:
Generate all pairs (start; end) where start < end
Generate all permutations of `n-2` values without start and end
For every permutation make {start, permutation.., end}
1 ... 2 + permutations of {3, 4}
1 3 4 2
1 4 3 2
1 ... 3 + permutations of {2,4}
1 2 4 3
1 4 2 3
...
3 ... 4 + permutations of {1, 2}
3 1 2 4
3 2 1 4
...

Related

Problem with my quicksort, it doesn't sort correctly

OK I am trying to make Prima algorithm so i need my edges array sorted, I tried to use quicksort here but it didn't work as I planned.
#include <iostream>
using namespace std;
void Sort (int arr[100][4], int m, int l) {
int i,j,x,v;
i=m;
j=l;
x=(i+j)/2;
do
{
while (((arr[i][3]<arr[x][3]))and(i<=l)) i++;
while (((arr[j][3]>arr[x][3]))and(j>=m)) j--;
if (i<=j)
{
v=arr[i][1];
arr[i][1]=arr[j][1];
arr[j][1]=v;
v=arr[i][2];
arr[i][2]=arr[j][2];
arr[j][2]=v;
v=arr[i][3];
arr[i][3]=arr[j][3];
arr[j][3]=v;
i++;
j--;
}
}
while (i<=j);
if (i<l) Sort(arr,i,l);
if (m<j) Sort(arr,m,j);
}
int main () {
int i,x,y,z,n,m;
int a[100][4];
fill(&a[0][0],&a[0][0]+400,0);
cout<<"Enter number of nodes and edges\n";
cin>>n>>m;
cout<<"Enter edges and their weights\n";
for (i=0;i<m;i++) {
cin>>x>>y>>z;
a[i][1]=min(x,y);
a[i][2]=max(x,y);
a[i][3]=z;
}
Sort (a,0,m-1);
for (i=0;i<m;i++) {
cout<<i+1<<") "<<a[i][1]<<' '<<a[i][2]<<' '<<a[i][3]<<endl;
}
return 0;
}
what I put is
5 10
1 2 4
1 3 7
4 1 5
5 1 8
2 3 3
2 4 6
2 5 6
3 4 8
3 5 2
4 5 4
what I get is
1) 3 5 2
2) 2 3 3
3) 1 4 5
4) 1 2 4
5) 4 5 4
6) 2 5 6
7) 2 4 6
8) 1 3 7
9) 1 5 8
10) 3 4 8
I don't understand why 5 is going ahead of 4's. Hope you could help.
You choose the pivot element in the middle of the (sub)array, which is fine, but you leave it in that position when you run the partitioning loop, and rely on it to stay there, which is not ok. With your approach, the pivot is likely to be swapped to a different position during the ordinary course of partitioning, after which the remainder of the partitioning will be based on the key swapped into the pivot's original position, which is likely to be different.
The usual approach is to start by swapping the pivot element to one end of the array or the other, partition the rest of the array, and then afterward swap the pivot into its correct position, as discovered via the partitioning process.
Change the code to use the pivot value instead of the pivot index, and some fixes to make it more like conventional Hoare partition scheme:
i=m-1;
j=l+1;
x=arr[(i+j)/2][3];
while(1)
{
while (arr[++i][3] < x);
while (arr[--j][3] > x);
if(i >= j)
return j;
// ...

Optimize triplet summation in C++

Problem
I need to compute a function of an array of integers. For every three-element subset (or triplet) of the array, I need to compute the term floor((sum of triplet)/(product of triplet)). Then I need to return the sum of all such terms.
Example
Input (length; array):
5
1 2 1 7 3
Output:
6
Explanation
The following triplets exist in the given array:
1 2 1
1 2 7
1 2 3
1 1 7
1 1 3
1 7 3
2 1 7
2 1 3
2 7 3
1 7 3
Considering these triplets from the sample input:
1 2 1 contributes 2, because floor((1+2+1)/(1*2*1)) = floor(4/2) = 2
1 2 3 contributes 1
1 1 7 contributes 1
1 1 3 contributes 1
2 1 3 contributes 1
All other triplets contribute 0 to the sum.
Hence the answer is (2+1+1+1+1)=6.
My Solution
What I tried is complexity O(n^3). Code is given below:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
long t,n[300005],sum=0,mul=1,i,j,k,res=0;
cin >> t;
for(i=0;i<t;i++)
cin >>n[i];
for(i=0;i<t-2;i++)
for(j=i+1;j<t-1;j++)
for(k=j+1;k<t;k++)
{
sum = n[i]+n[j]+n[k];
mul = n[i]*n[j]*n[k];
res += floor(sum/mul);
}
cout << res << endl;
return 0;
}
Is there any hint of better optimization?
While still O(n^3), you could save some operations by caching the redundant calculations between n[i] and n[j] as you iterate over n[k].
For example:
long sum_ij,mul_ij;
for(i=0;i<t-2;i++) {
for(j=i+1;j<t-1;j++) {
sum_ij = n[i]+n[j];
mul_ij = n[i]*n[j];
for(k=j+1;k<t;k++)
{
sum = sum_ij+n[k];
mul = mul_ij*n[k];
res += floor(sum/mul);
}
}
}

Using recursion combinations to subset array [duplicate]

This question already exists:
Recursion all combinations of lower triangle C++
Closed 8 years ago.
I recently posted a poor question on how to use recursion to estimate all combinations of lower triangle in C++. I managed to find a recursive algorithm that given an array of size n, generates and prints all possible combinations of r elements in array. I've employed this function using Rcpp in R. I've then written a loop around this function to get all the subsets of combinations r to r + n.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int recursive(IntegerVector arr, IntegerVector data, int start, int end, int index, int r)
{
if (index == r)
{
for (int j=0; j<r; j++)
printf("%d ", data[j]);
printf("\n");
}
for (int i=start; i<=end && end-i+1 >= r-index; i++)
{
data[index] = arr[i];
recursive(arr, data, i+1, end, index+1, r);
}
}
R code with five groups:
Rcpp::sourceCpp('recursive2.cpp')
nComm <- 5
r <- c(2:nComm)
n <- nComm
arr <- c(1:nComm)
dat <- c(1:nComm)
for(i in 1:(n-1)){
recursive(arr, dat, 0, n-1, 0, r[i])
}
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
1 2 3 4
1 2 3 5
1 2 4 5
1 3 4 5
2 3 4 5
1 2 3 4 5
Currently, this just prints the subsets of combinations I need to estimate my dissimilarities. I'd like to be able to remove the loop and use it as a single Rcpp function/script. With the end goal to be able to use the subsets (currently printed combinations) as way to subset rows in an array. Which will be used to calculate the intersect between vectors. So 1 2 will be used to compare rows 1 and 2 in an array. And so forth.

How to detect all possible subsets from a given vector?

I'm writing a function which should detect all possible subsets from a main vector and push them to another vector. The elements in the subsets are also added to each other before being pushed into the new vector(s1).
At the moment what my code does is the following..
For example, lets say myvec = {1,2,3}, then v1 = {1,3,6,2,5,3}. It only sums consecutive numbers. However I also want it to sum up combinations like 1 & 3 which would add a 4 to the vector v1. At the moment, I have not been able to modify my algorithm in a way that I can achieve that. Any help will be appreciated!
for (k=0; k<myvec.size(); k++) {
total = 0;
for (m=k; m<int_vec.size(); m++) {
total += myvec[m];
v1.push_back(total);
}
}
One way to think about the power set of a given (ordered) set is to think of its elements (the subsets) as bit vectors where the n-th bit is set to 1 if and only if the n-th element from the set was chosen for this subset.
So in your example, you'd have a 3 bit vector that could be represented as an unsigned integer. You'd “count the bit vector” up from 0 (the empty set) to 7 (the entire set). Then, in each iteration, you pick those elements for which the respective bit is set.
As can be readily seen, the power set explodes rapidly which will make it impractical to compute explicitly for any set with more than a dozen or so elements.
Casting these thoughts into C++, we get the following.
#include <climits> // CHAR_BIT
#include <iostream> // std::cout, std::endl
#include <stdexcept> // std::invalid_argument
#include <type_traits> // std::is_arithmetic
#include <vector> // std::vector
template<typename T>
std::vector<T>
get_subset_sums(const std::vector<T>& elements)
{
static_assert(std::is_arithmetic<T>::value, "T must be arithmetic");
if (elements.size() > CHAR_BIT * sizeof(unsigned long))
throw std::invalid_argument {"too many elements"};
const std::size_t power_size {1UL << elements.size()};
std::vector<T> subset_sums {};
subset_sums.reserve(power_size);
for (unsigned long mask = 0UL; mask < power_size; ++mask)
{
T sum {};
for (std::size_t i = 0; i < elements.size(); ++i)
{
if (mask & (1UL << i))
sum += elements.at(i);
}
subset_sums.push_back(sum);
}
return subset_sums;
}
int
main()
{
std::vector<int> elements {1, 2, 3};
for (const int sum : get_subset_sums(elements))
std::cout << sum << std::endl;
return 0;
}
You might want to use a std::unordered_set for the subset-sums instead of a std::vector to save the space (and redundant further processing) for duplicates.
The program outputs the numbers 0 (the empty sum), 1 (= 1), 2 (= 2), 3 (= 1 + 2), 3 (= 3), 4 (= 1 + 3), 5 (= 2 + 3) and 6 (= 1 + 2 + 3). We can make this more visual.
mask mask
(decimal) (binary) subset sum
–––––––––––––––––––––––––––––––––––––––––––––––––
0 000 {} 0
1 001 {1} 1
2 010 {2} 2
3 011 {1, 2} 3
4 100 {3} 3
5 101 {1, 3} 4
6 110 {2, 3} 5
7 111 {1, 2, 3} 6

I want to get every permutation of list elements via recursion

I want to get every permutation of my list's elements. I'm trying to do it by shuffling these elements between two lists and checking iterations of list2.
Something is wrong though. Can you help me to get right solution to my problem?
void iterlist(list<int>& Lit)
{
list<int>::iterator it;
for (it=Lit.begin(); it!=Lit.end(); it++)
cout << " " << *it;
cout << endl;
}
void permutations(list<int>& L1, list<int>& L2)
{
L2.push_back(L1.front());
L1.pop_front();
if(!L1.empty())
{
permutations(L1, L2);
}
L1.push_back(L2.back());
L2.pop_back();
iterlist(L2);
}
I was testing it for elements of L1 = 1,2,3,4,5, and the only permutations I get are: 1 2 3 4 5 and 5 4 3 2 1.
A general algorithm for recursively generating permutations of N-length from a list of N items is:
For each element x in list
Make a copy of list without element x; call it newList
Find all of the permutations of newList (thats the recursion, btw)
Add element x to the beginning of each permutation of newList
There are other ways of doing this, but this one I have consistently found the easiest for people learning recursion to wrap their heads around. The method you appear to be using involves storing the iterative loop portion of the algorithm in a second list, which is perfectly fine, but I warn you the algorithm for managing order-swapping is not immediately intuitive when doing that (as you'll no-doubt discover in due time).
The following demonstrates the general algorithm (and not particularly efficiently, but you can get the general idea from it).
#include <iostream>
#include <list>
typedef std::list<int> IntList;
void iterlist(IntList& lst)
{
for (IntList::iterator it=lst.begin(); it!=lst.end(); it++)
cout << " " << *it;
cout << endl;
}
std::list<IntList> permute(IntList& L1)
{
if (L1.size() == 1)
return std::list<IntList>(1,L1);
std::list<IntList> res;
for (IntList::iterator i = L1.begin(); i != L1.end();)
{
// remember this
int x = (*i);
// make a list without the current element
IntList tmp(L1.begin(), i++);
tmp.insert(tmp.end(), i, L1.end());
// recurse to get all sub-permutations
std::list<IntList> sub = permute(tmp);
// amend sub-permutations by adding the element
for (std::list<IntList>::iterator j=sub.begin(); j!=sub.end();j++)
(*j).push_front(x);
// finally append modified results to our running collection.
res.insert(res.begin(), sub.begin(), sub.end());
}
return res;
}
int main()
{
IntList lst;
for (int i=0;i<4;i++)
lst.push_back(i);
std::list<IntList> res = permute(lst);
for (std::list<IntList>::iterator i=res.begin(); i!=res.end(); i++)
iterlist(*i);
return 0;
}
Produces the following output, all permutations of 0..3:
3 2 1 0
3 2 0 1
3 1 2 0
3 1 0 2
3 0 2 1
3 0 1 2
2 3 1 0
2 3 0 1
2 1 3 0
2 1 0 3
2 0 3 1
2 0 1 3
1 3 2 0
1 3 0 2
1 2 3 0
1 2 0 3
1 0 3 2
1 0 2 3
0 3 2 1
0 3 1 2
0 2 3 1
0 2 1 3
0 1 3 2
0 1 2 3