Searching in vectors of pairs - c++

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
}

Related

How to convert a string of HashSet to a 2D vector in c++ ? This is a 3-sum problem in leetcode

// nums = [-1,0,1,2,-1,-4]
// result should be = {{-1,-1,2},{-1,0,1}}
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
unordered_set<string> s;
for(int start1=0; start1<nums.size(); start1++){
for(int start2=start1+1; start2<nums.size(); start2++){
for(int start3=start2+1; start3<nums.size(); start3++){
string str = "";
if(nums[start1]+nums[start2]+nums[start3] == 0){
str += to_string(nums[start1])+
to_string(nums[start2])+
to_string(nums[start3]);
}
s.insert(str); //s{"-1-12","-101"}
}
}
}
After inserting values to set s, s look as follows
s{"-1-12","-101"}
The problem is how I can convert that set to a 2d vector in c++.
I wanted to return a 2D vector of integers.
You want to return a 2D vector of integers and declare the function to return vector<vector<int>>, which is fine - but you never return anything from the function.
Instead of populating a vector<int> in your inner loop, you've chosen to populate a string. That must be changed.
Using an unordered_set<vector<int>> will however not work "out of the box" because there is no standard hashing function for vector<int>. I suggest using a set instead which only requires operator< to be defined, which it is for vector<int>.
"result should be = {{-1,-1,2},{-1,0,1}}" - but that's not what your algorithm produces. It produces {{},{-1,-1,2},{-1,0,1}} since it'll insert elements even when nums[start1]+nums[start2]+nums[start3] != 0.
Example with suggested fixes:
std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {
std::sort(nums.begin(), nums.end());
std::set<std::vector<int>> s; // using a set<vector<int>> instead
for (size_t start1 = 0; start1 < nums.size(); start1++) {
for (size_t start2 = start1 + 1; start2 < nums.size(); start2++) {
for (size_t start3 = start2 + 1; start3 < nums.size(); start3++) {
if (nums[start1] + nums[start2] + nums[start3] == 0) {
// only insert when a match is found to produce the
// expected result
s.insert({nums[start1], nums[start2], nums[start3]});
}
}
}
}
// populate the std::vector<std::vector<int>> by using the begin() and
// end() iterators of `s`:
return {s.begin(), s.end()};
}
Demo
Since copying the inner vector<int>s may be an expensive operation, you can, since C++17, also move them from the set<vector<int>> into the vector<vector<int>>.
std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {
std::sort(nums.begin(), nums.end());
std::set<std::vector<int>> s;
for (size_t start1 = 0; start1 < nums.size(); start1++) {
for (size_t start2 = start1 + 1; start2 < nums.size(); start2++) {
for (size_t start3 = start2 + 1; start3 < nums.size(); start3++) {
if (nums[start1] + nums[start2] + nums[start3] == 0) {
s.insert({nums[start1], nums[start2], nums[start3]});
}
}
}
}
std::vector<std::vector<int>> rv;
for(std::set<std::vector<int>>::iterator it = s.begin(), next;
it != s.end(); it = next)
{
next = std::next(it);
// extract and move:
rv.push_back(std::move(s.extract(it).value()));
}
return rv;
}
Demo

comparison of external value in count_if

I want to iterate through a vector and want to get count of greater elements in another vector. I tried below code snippet, unfortunately it does not work this way.
sort(begin(vec1),end(vec1));
sort(begin(vec2),end(vec2));
for(int i = 0; i < vec1.size(); i++)
{
int val = vec1[i];
count_if(begin(vec2),end(vec2),[](int x) { return (x > val); });
}
If you want to count how many elements in vec2is greater than the i'th element in vec1 then you are doing it correct and just have to capture val in the lambda
for(int i = 0; i < vec1.size(); i++)
{
int val = vec1[i];
auto res = count_if(begin(vec2),end(vec2), [val](int x) { return (x > val); });
}
but if you want to compare each element in vec2 with the corresponding element in vec1 you have to do it manually.
int count = 0;
//here the sizes of vec1 and vec2 must be equal
for (auto it1 = begin(vec1), it2 = begin(vec2); it1 != end(vec1); ++it1, ++it2) {
if (*it2 > *it1)
++count;
}
EDIT:
As #Jarod42 commented. It is possible to use an algorithm for the second case
auto res = std::transform_reduce(begin(vec2), end(vec2), begin(vec1), 0,
std::plus<>(), std::greater<>());

Sorting strings in ascending order by a certain value. What is wrong in my implementation?

I have the following problem :
Given a number N and N names, sort the names using a certain value (in ascending order). The names with the same value get sorted alphabetically.
The value of each name is determined by the number of pairs of vowels or consonants. Thus, each pair of vowels adds 1 to the value of the word, each pair of consonants subtracts 1 from the value, and a vowel-consonant or consonant-vowel pair doesn't change the value of the word.
What I did :
I created a vector using a struct. Each element has the name and its value. I calculated the value of each name and gave it to the .value field. After that, I sorted my vector using 2 for loops (I had no efficient idea for a value sort and an alphabetical sort all in one), and displayed the vector.
What happens:
I get no result, and I also think that there might be a segmentation fault. I'm still a newbie when it comes to finding out such errors.
Can you give me a few pointers ?
Thank you.
Attached the code below.
#include <vector>
#include <string>
#include <cstring>
using namespace std;
const char voc[] = "aeiouAEIOU";
struct stud
{
string name;
int value;
};
typedef vector<stud> vect;
void data(int& n, vect& v)
{
cin>>n;
for(int i = 0; i < n; ++i)
{
cin>>v[i].name;
}
}
int getValue(string name)
{
int value = 0;
int len = name.length();
for(int i = 0; i < len; ++i)
{
if(strchr(voc, name[i]) && strchr(voc, name[i+1]))
value++;
else if(!strchr(voc, name[i]) && !strchr(voc, name[i+1]))
value--;
}
return value;
}
void updateValues(vect& v)
{
vector<stud>::size_type v_size = v.size();
for(unsigned i = 0; i < v_size; ++i)
{
int value = getValue(v[i].name);
v[i].value = value;
}
}
void sortByValue(vect& v)
{
vector<stud>::size_type v_size = v.size();
for(unsigned i = 0; i < v_size; ++i)
for(unsigned j = i+1; j < v_size; ++j)
{
if(v[i].value > v[j].value)
swap(v[i], v[j]);
else if(v[i].value == v[j].value)
if(v[i].name.compare(v[j].name) > 0)
swap(v[i], v[j]);
}
}
void display(vect v)
{
vector<stud>::size_type sz = v.size();
for(unsigned i = 0; i < sz; ++i)
cout<<v[i].name<<'\n';
}
int main()
{
int n;
vect myvec;
data(n, myvec);
updateValues(myvec);
sortByValue(myvec);
display(myvec);
return 0;
}
better use overload operator> watch here
or use std::sort
std::vector<stud> vec;
//read
std::sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) -> bool
{
if (a.value == b.value)
return a.name > b.name;
else
return a.value > b.value
});

Dynamic Programming Solution for TSP in C++

I have been trying to implement Dynamic Programming solution for TSP (Travelling Salesperson Problem) in C++. My code compiles but when I try to run the object file the program stops working and I am forced to close it.
Here is the code:
int tsp(std::vector<std::vector<int>> matrix) {
int n = matrix[0].size();
std::vector<std::vector<int>> A; // Vertex, Set-Size
std::set<int> S;
for(int i = 0; i < n; ++i) {
S.insert(i);
}
for(int i = 0; i < n; i++) {
if(S.size() == 2) {
A[i][2] = matrix[1][i];
}
else if(S.size() > 2) {
std::set<int>::iterator it;
for(it = S.begin(); it != S.end(); ++it) {
int s = S.size();
S.erase(i);
int sd = S.size();
int k = *it;
if((k != i) && (k != 1) && (A[i][s] > (matrix[k][i] + A[k][sd]))) {
A[i][s] = matrix[k][i] + A[k][sd];
}
}
}
}
return A[1][n];
}
Can someone please point out what mistake I am making.
You need to fill or resize a std::vector before calling operator[int] on it. A vector is basically an array that holds its size. So any out of bound access will cause a segmentation fault in runtime (if you are lucky) or will corrupt your memory.
You have a vector of vectors here, so you will need to iterate over two ranges and fill (or resize) vectors properly:
std::vector<std::vector<int>> A; // Vertex, Set-Size
for(int i=size; i>0; --i)
A.push_back(std::vector<int>);
for(int i=size; i>0; --i)
for(int j=size; j>0; --j)
A[i][j] = 0;
Even better:
A.resize(size);
for(auto& v : a) // (since you already have c++11)
v.resize(size, val); // fill with val

all combinations of k elements out of n

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