Can somebody provide me a link or pseudocode of a function for finding all combinations of k elements out of n? possibly in STL. I don't need to compute n choose k, I need to list all vectors of numbers of size k.
Thanks
In C++ given the following routine:
template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
/* Credits: Thomas Draper */
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1,j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1,j,last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k,itr2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
You can then proceed to do the following:
// 9-choose-3
std::string s = "123456789";
std::size_t k = 3;
do
{
std::cout << std::string(s.begin(),s.begin() + k) << std::endl;
}
while(next_combination(s.begin(),s.begin() + k,s.end()));
Or for a std::vector of int's:
// 5-choose-3
std::size_t n = 5;
std::size_t k = 3;
std::vector<int> ints;
for (int i = 0; i < n; ints.push_back(i++));
do
{
for (int i = 0; i < k; ++i)
{
std::cout << ints[i];
}
std::cout << "\n";
}
while(next_combination(ints.begin(),ints.begin() + k,ints.end()));
http://howardhinnant.github.io/combinations.html
Search for "for_each_combination". If you find something faster, please let me know. Unlike other algorithms I often see, this one doesn't require the element type to be LessThanComparable.
Create an auxiliary vector with n - k zeros followed by k ones. A zero means the element in the original container is not included, whereas one means the element is included.
Now use std::next_permutation on the auxiliary vector to get the next combination.
Here is a lazy example of pseudocode that can get the job done...
void nChooseK(array[n],k){
recurse("",array[n],k);
}
void recurse(initialString,array[n],k){
if(k == 0){
print initialString;
return;
}
for(i=0;i<n;i++){
tmpArray = array[0...i-1]+array[i+1...];//the array without the object to remove
recurse(initialString + array[i], tmpArray,k-1)
}
}
You could use std::next_permutation but it is n! and not n choose k. You could filter them after you created them. But this solution is O(n!), not really perfect. Here is the trial and error solution:
int factorial(int value)
{
int result = 1;
for(int i = 1; i <= value; i++)
{
result *= i;
}
return result;
}
std::set<std::set<int>> binomial_coefficient(std::vector<int> input, int k)
{
std::set<std::set<int>> solutions;
for(unsigned int i = 0; i < factorial(input.size()); i++)
{
std::next_permutation(input.begin(), input.end());
solutions.insert(std::set<int>(input.begin(), input.begin() + k));
}
return solutions;
}
Related
I have a 2d vector of pairs and I would like get in which row is a given pair.
I tried to iterate through all the elements but I didn't succeed.
Here is the adjacency matrix of an undirected, weighted graph:
vector<pair<int,int >> adj[20];
for (int i = 1; i <= nodes; i++){
f >> x >> y >> weight;
adj[x].push_back(make_pair(weight, y));
adj[y].push_back(make_pair(weight, x));
}
And it looks like something like this:
(4,2),(5,3)
(4,1),(6,3)
(5,1),(6,2)
I am trying to find in which row is the pair (6,2)
typedef pair<int, int>p;
p pair= make_pair(6, 2);
cout << which_row(adj, pair);
Here is what I tried first:
int which_row(vector<p>adj[20], p pair) {
vector <pair<int, int>> ::iterator it;
for (int i = 0; i < adj->size(); i++) {
for (int j = 0; j < adj[i].size(); i++)
if (pair.first == adj[i][j].first && pair.second == adj[i][j].second)
return i;
}
return -1;
}
but it does not step in the for loop.
Second:
int which_row(vector<p>adj[20], p pair) {
vector <pair<int, int>> ::iterator it;
for (int i = 0; i <= adj->size(); i++) {
for (it = adj[i].begin(); it != adj[i].end(); it++)
if (pair.first == it->first && pair.second == it->second)
return i;
}
}
But it does not step in the second for loop.
What can I do?
Since we can infer your x and y inputs from the pairs you gave us, you never push anything into adj[0]. adj->size() is the same as adj[0].size(). You never pushed anything into this so it will be 0. It seems you want to go over every row? Each row contains a vector? Each vector contains some pairs? Make adj a vector<vector<pair<int, int>>> so you can access adj.size(). That's likely what you want. Or iterate from i = 0; i < 20; i++ to go over each row.
Change your iteration to:
int which_row(vector<p>adj[20], p pair) {
for (int i = 0; i < 20; i++) { // <-- changed to < 20 (not <= 20)
for (auto it = adj[i].begin(); it != adj[i].end(); it++)
if (pair == *it) // <-- pairs compare as you'd expect, no need to compare each element
return i;
}
return -1; // need to return something if not found
}
Or we can take advantage of std::find in the <algorithm> library:
#include <algorithm>
int which_row(vector<p>adj[20], p pair) {
for (int i = 0; i < 20; i++) { // <-- changed to < 20 (not <= 20)
if (std::find(adj[i].begin(), adj[i].end(), pair) != adj[i].end())
return i;
}
return -1; // need to return something if not found
}
If you change your adj initialization to std::vector<std::vector<p>> adj(20); you can change your which_row to:
// in main or whatever:
// makes a vector of 20 default-initialized (empty) vector<p>
std::vector<std::vector<p>> adj(20);
// elsewhere:
int which_row(vector<vector<p>> adj, p pair) {
for (auto i = 0; i < adj.size(); i++) { // <-- adj is a vector now
if (std::find(adj[i].begin(), adj[i].end(), pair) != adj[i].end())
return i;
}
}
return -1; // need to return something if not found
}
My multiway_merge function is incorrect but not sure why. Seems to be correct logically but if the sorting is correct then it must be the merging. I am supposed to make a min heap of the first element of each sorted vector and then add them to the output_list in the correct sorted order and keep doing that until all the numbers have been added to the output_list.
int partition(vector<int>& list, int first, int last) {
// The pivot should be the median of the
// first, middle, and last elements.
int middle = first + (last - first) / 2;
if (list[first] > list[middle])
swap(list[first], list[middle]);
if (list[first] > list[last])
swap(list[first], list[last]);
if (list[middle] > list[last])
swap(list[middle], list[last]);
swap(list[middle], list[first]);
int pivot = list[first];
int i = first - 1;
int j = last + 1;
while(true) {
do {
i++;
} while(list[i] < pivot);
do {
j--;
} while(list[j] > pivot);
if(i >= j)
return j;
swap(list[i], list[j]);
}
}
void quicksort(vector<int>& list, int first, int last) {
if(first < last) {
int pivotLocation = partition(list, first, last);
quicksort(list, first, pivotLocation);
quicksort(list, pivotLocation + 1, last);
}
}
void multiway_merge(vector<vector<int> >& input_lists,
vector<int>& output_list) {
int numLists = (int) (input_lists.size());
int numElements = (int) (input_lists[0].size());
priority_queue<int, vector<int>, greater<int> > minHeap;
for(int i = 0; i < numLists; i++) {
for(int j = 0; j < numElements; j++) {
minHeap.push(input_lists[i][j]);
if (minHeap.size() > numLists) {
output_list.push_back(minHeap.top());
minHeap.pop();
}
}
}
while (minHeap.size()) {
output_list.push_back(minHeap.top());
minHeap.pop();
}
}
int main(int argc, char** argv) {
int n, m;
cin >> n >> m;
vector<vector<int> > input_lists(n, vector<int>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> input_lists[i][j];
}
}
// Quicksort k sublists
for (int i = 0; i < input_lists.size(); ++i)
quicksort(input_lists[i], 0, m-1);
// Merge n input sublists into one sorted list
vector<int> output_list;
multiway_merge(input_lists, output_list);
for(int i = 0; i < output_list.size(); ++i)
cout << output_list[i] << " ";
cout << endl;
}
I couldn't find any logical error with your partition function, Maybe your problem source is in the way that you call this function from sort function and you didn't share that function with us so I had to guess.
Anyway, using your implementation of partition function the quick sort algorithm would be something like this :
#include <iostream>
#include <vector>
#include <algorithm>
int partition(std::vector<int> &vec, int low, int high)
{
int middle = low + (high - low) / 2;
if((vec.at(middle) >= vec.at(low) && vec.at(middle) <= vec.at(high))
|| (vec.at(middle) <= vec.at(low) && vec.at(middle) >= vec.at(high)))
std::swap(vec.at(high), vec.at(middle));
if((vec.at(high) >= vec.at(low) && vec.at(high) <= vec.at(middle))
|| (vec.at(high) <= vec.at(low) && vec.at(high) >= vec.at(middle)))
std::swap(vec.at(low), vec.at(high));
int pivot = vec.at(low);
int i = low - 1, j = high + 1;
while(true)
{
do
{
i++;
} while(vec.at(i) < pivot);
do
{
j--;
} while(vec.at(j) > pivot);
if(i >= j)
return j;
std::swap(vec.at(i), vec.at(j));
}
}
void quickSort(std::vector<int> &vec, int low, int high)
{
if(low < high)
{
int pi = partition(vec, low, high);
quickSort(vec, low, pi);
quickSort(vec, pi + 1, high);
}
}
int main()
{
std::vector<int> input = {10, 7, 15, 9, 1, 33};
quickSort(input, 0, input.size() - 1);
for(auto iter = input.begin(); iter != input.end(); ++iter)
std::cout << *iter << " ";
std::cout << "\n";
system("pause");
return 0;
}
EDIT : Your quick sort wasn't the source of the problem, You have problem merging sorted vectors, so the source of the problem is in logic of your multiway_merge function.
You used priority_queue to achieve this merge and it's a valid approach, but I think you miss understood how priority_queue actually works.
you can enqueue as many elements you want but the order of outgoing elements are determined by the way you set your priority. Take a loot at priority_queue.
Your compare condition to determine priority is right too, I mean using greater<int>. So the only problem in your code is one extra condition that you don't need it at all. I mean these lines of code :
if(minHeap.size() > numLists)
{
output_list.push_back(minHeap.top());
minHeap.pop();
}
Remove this condition and your multiway_merge will work fine. The final implementation of this function would be :
void multiway_merge(vector<vector<int> >& input_lists,
vector<int>& output_list)
{
unsigned int numLists = (int)(input_lists.size());
int numElements = (int)(input_lists[0].size());
priority_queue<int, vector<int>, greater<int> > minHeap;
for(int i = 0; i < numLists; i++)
{
for(int j = 0; j < numElements; j++)
{
minHeap.push(input_lists[i][j]);
}
}
while(minHeap.size())
{
output_list.push_back(minHeap.top());
minHeap.pop();
}
}
I have written a mergesort algo as follows but on compiling it I get the following ,which states
Expression: vector subscript out of range
I dont understand why I am getting this error, plz point out the mistakes,I have coded this algo based on my understanding of the mergesort algorithm
As per my understanding I have coded a recursive function(mergesort), in which each time the array in question is divided in two parts left and right namely and then the left and right arrays are subdivided further till the point where there is only 1 element present in the subarrays once this stage arrives the merge function is called to sort the partitioned arrays and merge it to the original array from which the arrays were partitioned and the recursion goes a step backward in the recursion tree
Here is the source code
#include<iostream>
#include<vector>
using namespace std;
class Soham
{
vector<int> v;
public:
Soham();
void merge(vector<int> &, vector<int> & ,vector<int> &);
void mergesort(vector<int> &);
};
Soham::Soham()
{
int no;
for (int i = 0; i < 5; i++)
{
cin >> no;
v.push_back(no);
}
mergesort(v);
cout << "result" << endl;
for (auto it = v.begin(); it != v.end(); it++)
cout << *it << " ";
}
void Soham::mergesort(vector<int> &v)
{
if (v.size() < 2)
return;
else
{
vector<int>left, right;
if (v.size() % 2 == 0)//if input size is even
{
auto it = v.begin() + (v.size() / 2);
left.assign(v.begin(),it);
right.assign(it, v.end());
}
else// if input size is odd
{
auto it = v.begin() + (v.size() / 2);
left.assign(v.begin(),next(it));
right.assign(next(it), v.end());
}
mergesort(left);
mergesort(right);
merge(left, right,v);
}
}
void Soham::merge(vector<int> &temp_left, vector<int> &temp_right,vector<int> &temp_main)
{
int i = 0, j = 0, k = 0;
while (i<= temp_left.size() && j <= temp_right.size())
{
if (temp_left[i] <= temp_right[j])
{
temp_main[k] = temp_left[i];
i++;
k++;
}
else
{
temp_main[k]=temp_right[j];
j++;
k++;
}
}
while (i <= temp_left.size())
{
temp_main[k]=temp_left[i];
i++;
k++;
}
while (j <= temp_right.size())
{
temp_main[k]=temp_right[j];
j++;
k++;
}
}
int main()
{
Soham a;
system("pause");
return 0;
}
Thanks For Help
while (i <= temp_left.size())
When you access vector at index size() you will get your out-of-bounds access
I can't know why this error happened in my code.(Actually, this is my first time to use std:: list.) When I use it++ it makes error 'list iterator outside of range', and when I use ++it it makes error 'list iterator not incrementable'. Please help me!
#include<stdio.h>
#include<stdlib.h>
#include<list>
#include<stack>
using namespace std;
typedef struct tag_vpos { int data; list <int>::iterator pos; } vpos;
list<int> row[100];
stack<vpos> save[100];
int col[100][100], n, r, rowsize[100];
//int row[100][100];
long long cnt;
void arr(int x, int y) {
list<int>::iterator it = row[y].begin();
while (it != row[y].end()) {
if (!col[x][*it]) {
vpos t = { *it, it }, temp;
int val = *it;
col[x][val] = 1;
row[y].erase(it++);
save[y].push(t);
if (x == r - 1) { // if x th column is the end of right
if (y == r - 1) cnt++; // if y th column is the bottom, count this
else arr(0, y + 1);// else fill next row, first column
}
else { arr(x + 1, y); } // else fill next right square
temp = save[y].top();
row[y].insert(temp.pos, temp.data);
save[y].pop();
col[x][temp.data] = 0;
}
else it++;
}
return;
}
void main() {
printf("Input n, r (paint r x r field with n colors, same color cannot be used in same column and row) \n: ");
scanf("%d %d", &n, &r);
for (int i = 0; i < r; i++) {
for (int j = 0; j < n; j++) row[i].push_back(j);
rowsize[i] = n;
}
printf("start\n");
arr(0, 0);
printf("There are %ld ways to paint.\n", cnt);
}
To remove elements from STL container while iterating you combine the container's erase function (they all have this) with the remove or remove_if algorithm. Otherwise your invalidating your iterators underneath yourself.
void delete_elements(std::list &list)
{
list.erase(
std::remove_if(
list.begin(),
list.end(),
[](char x){return std::isspace(x);}),
list.end() );
}
Here is the program to find the pairs that sums up to 3.
For example:
INPUT : 0,3,5,1,2,4
OUTPUT: 0,3,1,2.
That means it should return all the pairs whose sum is equal to 3.
But I want to reduce the time complexity of this program. Right now I am using two nested for loops.
Can anyone suggest a better method to reduce the time complexity.
#include<iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
vector<int> r;
int x;
cout << "Enter the elements";
for(int i = 0; i < 6; i++)
{
cin >> x;
v.push_back(x);
}
for(int i = 0 ; i < v.size() - 1; i++)
{
for(int j = i + 1; j < v.size(); j++)
{
if(v[i] + v[j] == 3)
{
r.push_back(v[i]);
r.push_back(v[j]);
}
}
}
cout << "\noutput\n";
for(int i = 0 ; i < r.size(); i++)
{
cout<<r[i]<<"\n";
}
}
I'd do two preparation steps; First, eliminate all numbers > 3, as they will not be part of any valid pair. This reduces the complexity of the second step. Second, sort the remaining numbers such that a single walk through can then find all the results.
The walk through approaches the pairs from both ends of the sorted array; if a pair is found, both bounds can be narrowed down; if the current endings do sum up to a value > 3, only one boundary is narrowed.
Runtime complexity is O(N logN), where N is the count of elements <= 3; O(N logN) basically comes from sorting; the two single walk throughs will not count for large Ns.
int main(int argc, char* argv[]) {
const int N = 3;
std::vector<int> input{ 0,3,5,1,2,4};
std::vector<int>v(input.size());
int t=0;
for (auto i : input) {
if (i <= N) {
v[t++]=i;
}
}
std::sort (v.begin(), v.end());
long minIdx = 0;
long maxIdx = v.size()-1;
while (minIdx < maxIdx) {
int minv = v[minIdx];
int maxv = v[maxIdx];
if (minv+maxv == 3) {
cout << minv << '+' << maxv << endl;
minIdx++;maxIdx--;
}
else
minIdx++;
}
return 0;
}
You are searching for all the combinations between two numbers in n elements, more specifically, those that sum up to specific value. Which is a variation of the subset sum problem.
To make this happen you could generate all combinations without repetitions of the indexes of the vector holding the values. Here is an example of how to do this recursively and here is an example of how to do it iteratively, just to get an idea and possibly use it as a benchmark in your case.
Another approaches are dynamic programming and backtracking.
Late answer but works for negative integers too... For first, find the smallest number in the std::vector<int>, then like this answer says, remove all elements (or copy the opposite), which are higher than 3 + minimum. After sorting this std::vector<int> iterate through it from both ends with condition shown bellow:
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
std::vector<int> findPairs(const std::vector<int>& input, const int sum) {
int minElem = INT_MAX;
for(auto lhs = input.begin(), rhs = input.end() - 1; lhs < rhs;
++lhs, --rhs) {
const int elem = (*lhs < *rhs ? *lhs : *rhs);
if(elem < minElem)
minElem = elem;
}
std::vector<int> temp(input.size());
const auto tempBegin = temp.begin();
const auto tempEnd = std::remove_copy_if(input.begin(), input.end(),
temp.begin(), [minElem, sum](int elem) {
return (elem + minElem) > sum;
});
std::sort(tempBegin, tempEnd);
std::vector<int> result;
auto leftIter = tempBegin;
auto rightIter = tempEnd - 1;
while(leftIter < rightIter) {
if(*leftIter + *rightIter == sum) {
result.push_back(*leftIter++);
result.push_back(*rightIter--);
}
else {
if(sum - *leftIter < *rightIter) rightIter--;
else leftIter++;
}
}
return result;
}
int main() {
auto pairs = findPairs({ 0, 3, 5, 1, 2, 4, 7, 0, 3, 2, -2, -4, -3 }, 3);
std::cout << "Pairs: { ";
for(auto it = pairs.begin(); it != pairs.end(); ++it)
std::cout << (it == pairs.begin() ? "" : ", ") << *it;
std::cout << " }" << std::endl;
}
The code above will results the following:
Pairs: { -4, 7, -2, 5, 0, 3, 0, 3, 1, 2 }
I think you can solve this in O(n) with a map.
public void printPairs(int[] a, int v)
{
map<int, int> counts = new map<int, int>();
for(int i = 0; i < a.length; i++)
{
if(map.count(a[i]) == 0)
{
map[a[i]] = 1;
}
else
{
map[a[i]] = map[a[i]] + 1;
}
}
map<int, int>::iterator it = map.begin();
while(it != map.end())
{
int v1 = it->second;
if (map.count(v - v1) > 0)
{
// Found pair v, v1
//will be found twice (once for v and once for v1)
}
}
}