How do i Pass a set<int> var to a function? - c++11

The function dfs() in this program operates upon the set A & array C. The program works fine when set A and int C[MAX] are declared global. But when i try to use this program t number of times, the set A and C are initialized with previous test cases's values, which gives wrong output. How can i make this program to accept new values in A & C for every next case. Note: This program is intended to find if the graph with n number of nodes and m number of edges is bipartite or not.
#include <bits/stdc++.h>
using namespace std;
const int MAX=1000000; // maximum number of vertices
int dfs(int x,const set<int>& A,int C[]){
for(int y:A[x]){
if(C[y]==C[x])return 0;// this means the graph is not bipartite
if(C[y]==0){
if(C[x]==1) C[y]=2;
else C[y]=1;
dfs(y,A,C);
return 1;
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--)
{
set<int> A[MAX];// Here, i declare set<int> A and Int C[MAX] in local scope
int C[MAX];
// Passing set<int> A and int C[] to dfs()..
int res = dfs(i,A,int C);
}
If i change my code to something like above. I get the following error.
prog.cpp: In function 'int dfs(int, const std::set<int>&, int*)':
prog.cpp:8:16: error: no match for 'operator[]' (operand types are 'const std::set<int>' and 'int')
for(int y:A[x]){

According to the c++ doc, set - C++ Reference there is not such operator[] in std::set<>so your for(int y:A[x]) is wrong. You cannot call A[x].
I'd recommend to use an vector or some other container meeting your requirement instead of a std::set

Related

Hashing using int array or unordered_map in STL?

Which is more efficient in terms of memory and time complexity hashing using int array or unordered_map in STL?
By hashing I mean storing elements formed by the combination of a key value and a mapped value, and fast retrieval of individual elements based on their keys.
Actually I was trying to solve this question.
Here's my solution:-
#include <bits/stdc++.h>
#define MAX 15000005
using namespace std;
/*
* author: vivekcrux
*/
int gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
int c[MAX];
int n;
int sieve()
{
bitset<MAX> m;
m.set();
int ans = 0;
for(int i=2;i<MAX;i++)
{
if(m[i])
{
int mans = 0;
for(int j=i;j<MAX;j+=i)
{
m[j]=0;
mans += c[j];
}
if(mans<n)
ans = max(ans,mans);
}
}
return ans;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int i,j;
cin>>n;
int a[n+1];
for(i=0;i<n;i++)
{
cin>>a[i];
}
int g = a[0];
for(i=1;i<n;i++)
{
g = gcd(g,a[i]);
}
for(i=0;i<n;i++)
{
a[i] /= g;
if(a[i]!=1) c[a[i]]++;
}
int m = sieve();
if(m==0)
cout<<"-1";
else
cout<<n - m<<endl;
return 0;
}
In this code if I use
unordered_map<int,int> c;
instead of
int c[MAX];
I get a Memory limit exceeded verdict.I have found here that unordered_map has a constant average time complexity on average, but no details about space complexity is mentioned here.I wonder why am I getting MLE with unordered_map.
unordered_map uses bucket to store values. A bucket is a slot in the container's internal hash table to which elements are assigned based on the hash value of their key. Lets see the following code in C++17.
#include <bits/stdc++.h>
using namespace std;
int main() {
unordered_map<int,int> mp;
mp[4] = 1;
mp[41] = 5;
mp[67] = 6;
cout<<mp.bucket_count();
}
The output comes out be 7 (depends on compiler). This is the number of buckets used in the above code. But if we use an array of size 67, it will obviously take more memory. Another case would be that if we would had numbers 1, 2 and 3 instead of 4, 41 and 67, the output would have been 7. Here using array was the way to go for saving space. So it depends on the keys you are storing in the hash table. For time complexity, both performs equally same. There is a collision condition in unordered_map which would blow the overall time complexity of the code. Here is the codeforces link of the blog.

std::array in template specialization

I want to write a function that take n int as a coordinate of array with the max value for each coordinate. This function linearizes these parameters to target a specific index.
int my_func(int x, int y, int XMAX, int YMAX){
return x + y*XMAX;
}
Here is a 2D example, but I can make something generic thanks to variadic template quite easily.
However, I am stucked when I want to make the same function that does not take the max value for each coordinate in parameters.
Something like that :
template<int XMAX, int YMAX>
int my_func(int x, int y){
return x + y*XMAX;
}
Here it works in 2D, but I want to generalize that from 1 to N dimensions and I don't know how I could achieve that.
I was thinking to pass an int N which is the number of dimension and an std::array<N, int>::iterator which is an iterator on the std::array containing the actual max value, but it does not compile.
Here is the code:
template <int N, std::array<size_t, N>::iterator it>
void foo(){...}
It says ’std::array<long unsigned int, N>::iterator’ is not a type.
If i just pass the std::array, I get the following error : ’struct std::array<long unsigned int, N>’ is not a valid type for a template non-type parameter
Does someone have an idea on how to solve such a problem ? I am using C++ 11 (G++ 5.4.0).
First of all, I suppose you did a little mistake in your function, because if you need to linearize the accessing of array you need to multuply y by XMAX
int my_func(int x, int y, int XMAX, int YMAX){
return x + y*XMAX;
}
because each row is composed of XMAX items. For answer to your question I used a template parameter pack
template <int N>
int my_func(int x)
{
assert(x < N);
return x;
}
template <int N, int... Ns, typename ARG, typename... ARGS>
ARG my_func (ARG x, ARGS... args)
{
assert(x < N);
return x + N*my_func<Ns...>(args...);
}
int main()
{
int a = 1;
int b = 2;
int c = my_func<10, 3>(a, b);
}
The fist function is the base for the recursion, the second function use two parameter packs but also 2 explicit template parameter to make the recursion possible.

Is it possible to put std::list::iterator into std::set?

Is it possible to put the iterator of list in to set:
I wrote codes as follows :
It failed on VS2015 but run smoothly on g++
And I also tried to use std::hash to calculate a hash value of std::list::iterator
but failed again, it has no hash func for iterator.
And one can help ? Or it's impossible .....
#include <set>
#include <list>
#include <cstring>
#include <cassert>
// like std::less
struct myless
{
typedef std::list<int>::iterator first_argument_type;
typedef std::list<int>::iterator second_argument_type;
typedef bool result_type;
bool operator()(const std::list<int>::iterator& x,const std::list<int>::iterator& y) const
{
return memcmp(&x, &y, sizeof(std::list<int>::iterator)) < 0; // using memcmp
}
};
int main()
{
std::list<int> lst = {1,2,3,4,5};
std::set<std::list<int>::iterator,myless> test;
auto it = lst.begin();
test.insert(it++);
test.insert(it++);
assert(test.find(lst.begin()) != test.end()); // fail on vs 2015
auto it1 = lst.end();
auto it2 = lst.end();
assert(memcmp(&it1,&it2,sizeof(it1)) == 0); // fail on vs 2015
system("pause");
return 0;
}
Yes, you can put std::list<T>::iterator in a std::set, if you tell std::set what order they should be in. A reasonable order could be std::less<T>, i.e. you sort the iterators by the values they point to (obviously you then can't insert an std::list::end iterator). Any other order is also OK.
However, you tried to use memcmp, and that is wrong. The predicate used by set requires that equal values compare equal, and there is no guarantee that equal iterators (as defined by list::iterator::operator==) also compare equal using memcmp.
I find a way to do this as like but not for the end iterator
bool operator<(const T& x, const T& y)
{
return &*x < &*y;
}

How to use a set of boost::dynamic_bitsets?

I'm trying to use a set of dynamic_bitset objects, but I'm getting an assertion failure at runtime:
a.out: boost/dynamic_bitset/dynamic_bitset.hpp:1291:
bool boost::operator<(const boost::dynamic_bitset<Block, Allocator>&,
const boost::dynamic_bitset<Block, Allocator>&)
[with Block = long unsigned int,
Allocator = std::allocator<long unsigned int>]:
Assertion `a.size() == b.size()' failed.
Here is the code:
#include <iostream>
#include <set>
#include <boost/dynamic_bitset.hpp>
int main() {
typedef boost::dynamic_bitset<> bitset;
std::set<bitset> myset;
bitset x(2, 0);
bitset y(3, 1);
myset.insert(x);
myset.insert(y);
return 0;
}
I'm wondering why the same size for the inserted dynamic_bitset objects is required. For the operator< to work, couldn't it assume that the most significant bits in the shorter bitset are implicitly filled with zeros?
Is there any way to do get that set of dynamic_bitsets to work?
I've also tried an unordered_set because it doesn't need the operator< but it can't compile because dynamic_bitset doesn't have a hash_value and I'm not sure how to write that without using its to_ulong member function, which would work only for short bitsets.
The reason for the assertion is the way the operator< is implemented:
for (size_type ii = a.num_blocks(); ii > 0; --ii)
Only the block count of the first operand is used to iterate through the bitsets.
If the size of the first bitset is larger, it would access the second bitset out of bounds.
You can define and use your own comperator with std::set and handle the comparison of different sized bitsets as you see fit:
struct my_less {
bool operator()(const boost::dynamic_bitset<>& lhs,
const boost::dynamic_bitset<>& rhs) const
{
//TODO: implement custom comparison for lhs < rhs
return false;
}
};
typedef boost::dynamic_bitset<> bitset;
std::set<bitset,my_less> myset;
myset.insert( bitset(2, 0) );
myset.insert( bitset(3, 1) );

GSL Uniform Random Number Generator

I want to use GSL's uniform random number generator. On their website, they include this sample code:
#include <stdio.h>
#include <gsl/gsl_rng.h>
int
main (void)
{
const gsl_rng_type * T;
gsl_rng * r;
int i, n = 10;
gsl_rng_env_setup();
T = gsl_rng_default;
r = gsl_rng_alloc (T);
for (i = 0; i < n; i++)
{
double u = gsl_rng_uniform (r);
printf ("%.5f\n", u);
}
gsl_rng_free (r);
return 0;
}
However, this does not rely on any seed and so, the same random numbers will be produced each time.
They also specify the following:
The generator itself can be changed using the environment variable GSL_RNG_TYPE. Here is the output of the program using a seed value of 123 and the multiple-recursive generator mrg,
$ GSL_RNG_SEED=123 GSL_RNG_TYPE=mrg ./a.out
But I don't understand how to implement this. Any ideas as to what modifications I can make to the above code to incorporate the seed?
The problem is that a new seed is not being generated. If you just want a function that returns a darn random number, and care nothing about the sticky details of how it's generated, try this. Assumes that you have the GSL installed.
#include <iostream>
#include <gsl/gsl_math.h>
#include <gsl/gsl_rng.h>
#include <sys/time.h>
float keithRandom() {
// Random number function based on the GNU Scientific Library
// Returns a random float between 0 and 1, exclusive; e.g., (0,1)
const gsl_rng_type * T;
gsl_rng * r;
gsl_rng_env_setup();
struct timeval tv; // Seed generation based on time
gettimeofday(&tv,0);
unsigned long mySeed = tv.tv_sec + tv.tv_usec;
T = gsl_rng_default; // Generator setup
r = gsl_rng_alloc (T);
gsl_rng_set(r, mySeed);
double u = gsl_rng_uniform(r); // Generate it!
gsl_rng_free (r);
return (float)u;
}
Read 18.6 Random number environment variables to see what that gsl_rng_env_setup() function is doing. It is getting a generator type and seed from environment variables.
Then see 18.3 Random number generator initialization - if you don't want to get the seed from an environment variable, you can use gsl_rng_set() to set the seed.
A complete answer to this question with a sample code can be seen in in this link.
Just for completeness I am putting a copy of the code for a function to create a seed here. It is written by Robert G. Brown: http://www.phy.duke.edu/~rgb/ .
#include <stdio.h>
#include <sys/time.h>
unsigned long int random_seed()
{
unsigned int seed;
struct timeval tv;
FILE *devrandom;
if ((devrandom = fopen("/dev/random","r")) == NULL) {
gettimeofday(&tv,0);
seed = tv.tv_sec + tv.tv_usec;
} else {
fread(&seed,sizeof(seed),1,devrandom);
fclose(devrandom);
}
return(seed);
}
But from my own experience with this function, I would say that the dev/random solution is very time consuming compared to the gettimeofday(), you can check it out. So, the gettimeofday() solution, might be better for you if its level of accuracy is enough:
#include <stdio.h>
#include <sys/time.h>
unsigned long int random_seed()
{
struct timeval tv;
gettimeofday(&tv,0);
return (tv.tv_sec + tv.tv_usec);
}

Resources