how to deal with map of map? - c++

I'm trying to find a solution for this problem
http://codeforces.com/problemset/problem/159/A
To find the solution, I thought of presenting the input by making a map of map.
And for this input my map should appear like this:
m["vasya"]={{"petya",1}}
m["petya"]={{"vasya",2}}
m["anya"]={{"ivan",2}}
m["ivan"]={{"anya",4}}
Below is my code.
and my assignment code:
// m[s1]=(ii(s2,t));
is wrong
my question is how can i assign to the map of map?
#include<iostream>
#include <cstdio>
#include <map>
#include <set>
#include <string>
#include<vector>
using namespace std;
int main(){
typedef map<string, int> ii;
map<string, ii> m;
int n,d;
cin>>n>>d;
string s1,s2,t;
for(int i=0;i<n;i++)
{
cin>>s1>>s2>>t;
// m[s1]=(ii(s2,t));
}
return 0;
}
Could anyone help?

You can write it like this:
m[s1][s2] = t;
I'm assuming you meant int t; rather than string t; since the last type in your map is int.

You want to make a more descriptive typedef than ii, but specifically you just want to add a new key-value pair into the map:
m[s1].insert(std::make_pair(s2, t));
Or if you want to split it up for clarity:
ii& submap = m[s1];
submap[s2] = t;
Or, if C++11 is available to you, exactly what you expressed in your question:
m[s1] = {{s2, t}};

Related

using std::accumulate when there is pointer

Is this the only solution when there is a pointer that points to a vector and we would like to use accumulate to sum up numbers?
Is there any simpler solution rather than writing a lambda function and using a four argument type of accumulating?
Also, for using std::sort, will the situation be the same?
Here is the code:
#include <random>
#include <vector>
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
const int N=3;
auto p=make_unique<array<int,N>> ();
(*p)[0]=3;
(*p)[1]=4;
(*p)[2]=5;
sum=accumulate(p,?,0);
return 0;
}
To answer your immediate question:
std::accumulate(p->begin(), p->end(), 0);
The same syntax will work for other STL algorithms as well.
Other improvements to your code snippet:
Avoid using #include<bits/stdc++.h>, see this post. Similarly for using namespace std, it's considered bad practise.
const N=3 -> const auto N=3
std::array is not a vector and you can initialise it directly using initializer-list syntax:
const auto* obj = new std::array<int,3>{3,4,5};

How to make a list of stacks in C++?

I'm trying to make a list of stacks in C++ using the code below , but I'm getting the error
main.cpp:17:13: error: ‘__gnu_cxx::__alloc_traits > >::value_type {aka class std::stack}’ has no member named ‘push_back’
vs[i-1].push_back(s);
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<stack<int>> vs;
for(int i=1; i<4; i++)
{
stack<int> s;
s.push(i*2);
s.push(i*3);
s.push(i*4);
vs[i-1].push_back(s);
}
return 0;
}
you can't use this line:-
vs[i-1].push_back(s);
Either define the size of the list earlier.
For Eg
vector<stack<int> > vs(100);
else only write
vs.push_back(s);
Updated Solution
#include <iostream>
#include<stack>
#include<vector>
using namespace std;
int main()
{
vector< stack<int> > vs;
for(int i=1; i<4; i++)
{
stack<int> s;
s.push(i*2);
s.push(i*3);
s.push(i*4);
vs.push_back(s);
}
return 0;
}
First of all, your vector is empty, any indexing in it will be out of bounds and lead to undefined behavior.
Secondly, vs[any_valid_index] is a stack and not a vector.
What you probably want is
vs.push_back(s);
Its not a fact for only vector of stacks. It is actually basic property of vector. You have two options to add value into vector.
If you don't declare size of vector (what you did) like
vector<stack<int>> vs;
stack<int>s;
Then you can insert by using vs.push_back(s) It will automatically handle the index.
Another way is you can declare the size of the vector first. like
vector<stack<int>> vs(sz); //size(sz) is defined by user
stack<int>s;
Then you can insert by using vs[index]= s This time you have to manually handle the index.

is there any way to define dynamic array without Determine the size of it

I need a dynamic array that I don't have to scale(Determine) to a fixed number like the following
string* s;
I have this code so far, but obviously it doesn't work.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
fstream f;
f.open("resa.txt");
string* s;
int i = 0;
while (f.good())
{
f >> *(s + i);
i++;
}
return 0;
}
This is my task:
Now we change the class definitions a bit. No static arrays can occur anymore. The fact that the arrays instead become dynamic means that some class methods need to be modified, and that some / some of the classes need copy constructors and assignment methods (or superimposed assignment operator). [...]"
This means, that I just can't use data structures.
It's not automatic, you have to allocate more memory every time you want to resize, copy elements into new array and delete the old one. Fortunately, standard library got you covered with std::vector - an automatically resizable array.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
fstream f;
f.open("resa.txt");
string temp;
std::vector<std::string> s;
while (f >> temp)
{
s.push_back(temp);
}
return 0;
}
I also fixed your input reading - see Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong? (applies to good() as well).
Alternatively, you can use std::istream_iterator to initialize vector in one line instead of using loop (credit to Ayxan):
vector<string> s{ istream_iterator<string>{f}, {} };

multi dimensional list c++ STL list

whats wrong with this simple program. I want to create multi list and insert using c++ STL. its giving segmentation fault.
#include <iostream>
#include <list>
using namespace std;
int main(){
list<int> *l;
l[0].push_back(1);
l[10].push_back(12);
cout<<endl;
return 0;
}
Why are you using a pointer to a list? You didn't allocate memory for the list. You could use a container to store multiple lists, e.g. std:array for static number of elements or std::vector for dynamic number of elements:
#include <array>
#include <iostream>
#include <list>
#include <vector>
using std::array;
using std::vector;
using std::list;
using std::cout;
int main(){
std::array<list<int>, 11> l;
l[0].push_back(1);
l[10].push_back(12);
std::vector<list<int>> l2(11);
l2[0].push_back(1);
l2[10].push_back(12);
cout << '\n';
return 0;
}
list<int> *l; makes l a pointer to a list<int> but it doesn't actually create a list<int> - and definitely not an array of list<int> which you are trying to access.
Possible solutions.
Plain C fixed size arrays of list<int>:
#include <iostream>
#include <list>
int main() {
std::list<int> l[11]; // place for 11 list<int>`'s
l[0].push_back(1);
l[10].push_back(12);
}
Using the C++ fixed sized std::array:
#include <array>
#include <list>
int main() {
std::array<std::list<int>, 11> l; // place for 11 list<int>'s
l[0].push_back(1);
l[10].push_back(12);
}
Using a C++ std::vector that allows for dynamicially adding more list<int>'s:
#include <list>
#include <vector>
int main() {
std::vector<std::list<int>> l(11); // starts with place for 11 list<int>'s
l[0].push_back(1);
l[10].push_back(12);
}
In list<int> *l; is creating a pointer to a list. Before accessing l you need to assign valid address to it.
Something like this,
list<int> l;
list<int> *l2 = &l;
list<int> *l; is a pointer to list, it is not initialized, so adding elements to it has undefined behaviour. Either you initialize it to a variable like:
list<int> l;
l.push_back(1);
l.push_back(12);
In this case you can only access the elements that already have data, l[0] or l[1].
Or you need to allocate space to the number of elements you need in your list.
For instance:
list<int> l[20];
l[0].push_back(1);
l[10].push_back(12);

what is the type of back_inserter(container)

My following code compiles but I do not know how to write this without using decltype. I have written my failed attempts in commented lines below the line which uses decltype.
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
template<class Out>
class Fill{
public:
Fill(){}
void fill(Out x){
for(int i = 0; i != 10; i++)*x++ = i;
}
};
int main(){
vector<int> v;
Fill<decltype(back_inserter(v))> f; //works
//does not work
//Fill<vector<int>::iterator> g;
//does not work
//Fill<back_insert_iterator<vector<int>> h;
f.fill(back_inserter(v));
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
}
Thanks
suresh
The type will be back_insert_iterater<vector<int> >. Your 3rd example doesn't work because you need a whitespace between the ">>". See http://www.cplusplus.com/reference/std/iterator/back_insert_iterator/, it simply holds a pointer to the container type and redefines operator= to be container.push_back. I believe this is present so that std containers can work with std algorithms. But, since you have control the definition to Fill you could simply allow the Fill class to hold a container pointer and call push_back directly against the container.
vector<int> ints;
typedef back_insert_iterator<vector<int>> InserterType; // This is what you need.
Fill<InserterType> f;
f.fill(back_inserter(ints));
copy(ints.begin(), ints.end(), ostream_iterator<int>(std::cout, "\n"));
If you are using c++0x, the answer is: 'auto' :D
I figured out that the mistake in my original post was that I missed the 3rd right angled bracket in the definition of h. It should be corrected as
Fill<back_insert_iterator<vector<int>>> h;
Now the code would compile and work as intended.