orDer oF succeSsion — CodinGame C++ Implementation
The problem is from CodinGame with difficulty level Medium.
Problem:
You have to output the order of succession to the British throne of a list of given people. The order is simple: From a descendant A, the next in the order is A’s first child B. Then, the next one is B’s first child C if any and so on. If C has no child, then the next one is B’s second child D. Then D’s children if any. Then B’s third child E… then A’s second child F…
Let’s draw it with a tree:
You see the order of succession: begin on the left of the tree, walk to the next level whenever possible otherwise continue to the right. Repeat until the whole tree is covered. Thus, the order is A-B-C-D-E-F.
In fact, in siblings of the same person, the male descendants are ordered before the female descendants. For example, if the order of birth of the children (M for male, F for female) is Fa Ma Me Fe then the order of succession in these siblings is Ma Me Fa Fe.
Ordering rules
(a) in order of generation
(b) in order of gender
(c) in order of age (year of birth)
Outputting rules
(a) exclude dead people (but include siblings of dead people)
(b) exclude people who are catholic (but include siblings of catholic people)
Constraints
Exactly one people does not have a parent (the parent’s name is replaced by the hyphen-
).
Read full problem here : orDer oF succeSsion
Solution:
Each person has name, parent name, year of birth and death etc. We will store these details in a struct Details.
struct Details
{
std::string name;
std::string parent_name;
int birth; // year of birth
std::string death;
std::string religion;
std::string gender;
int index;
bool has_child = false;
bool processed = false;
Details * parent;
Details * sibling;
Details * first_child;
Details(){}
Details(std::string name_, std::string parent_name_, int birth_, std::string death_, std::string religion_, std::string gender_, int index_):
name(name_), parent_name(parent_name_), birth(birth_), death(death_), religion(religion_),
gender(gender_), index(index_), parent(nullptr), sibling(nullptr), first_child(nullptr) {}
};
In main
function, we enter data in a vector of Details
.
std::vector<Details> family_details;
The person whose parent doesn’t exist in family_details
is the first ruler. We will store the index of that person in an integer variable first_ruler_index
.
int first_ruler_idx;
for (int i = 0; i < n; i++)
{
std::string name;
std::string parent;
int birth;
std::string death;
std::string religion;
std::string gender;
std::cin >> name >> parent >> birth >> death >> religion >> gender; std::cin.ignore();
if (parent == "-")
{
first_ruler_idx = i;
}
family_details.push_back( Details(name, parent, birth, death, religion, gender, i));
}
Function order_of_succession:
In this function, we have passed vector of Details
and an integer variable first_ruler_idx
as parameters. This function returns vector of strings in the order of succession.
First we declare a vector of strings rulers
and an integer variable curr_ruler_idx
.
Then it calls map_parent_children
function.
Function map_parent_children
will map the ruler at curr_ruler_idx
with his/her children.
Now we will start ordering rulers.
A person is eligible to rule if he/she is not dead, his/her religion is not Catholic. While processing we have to make sure the same person is not processed twice, so boolen variable processed
for that person is set to true once he/she is processed.
All this processing is done in a while
loop, whose condition is always true
.
while (true)
{
if (family[curr_ruler_idx].death == "-" &&
family[curr_ruler_idx].religion != "Catholic" && !family[curr_ruler_idx].processed)
{
rulers.push_back(family[curr_ruler_idx].name);
}
family[curr_ruler_idx].processed = true;
...
...
...
}
Once the ruler at curr_ruler_idx
is added to the vector ruler
. We have to check if he/she has a child or not. If he/she has child then the value of curr_ruler_idx
is updated to the index of the first_child
.
The siblings are already ordered according to their age and gender in map_parent_children
function.
while (true)
{
...
if (family[curr_ruler_idx].has_child)
{
curr_ruler_idx = family[curr_ruler_idx].first_child->index;
}
else
{
...
}
map_parent_children(family, curr_ruler_idx);
}
If current ruler does not have a child then we will check for his/her sibling. If he/she has sibling then curr_ruler_idx
is updated to the index of next sibling.
while (true)
{
...
if (family[curr_ruler_idx].has_child)
{
...
}
else
{
if (family[curr_ruler_idx].sibling != nullptr)
{
curr_ruler_idx = family[curr_ruler_idx].sibling->index;
}
else
{
...
}
}
If current ruler does not have sibling, then sibling to his/her parent will be the next ruler. If his/her parent does not have sibling then we check for grandparent and so on.
Before processing we have to make sure that the current ruler is not equal to first ruler. If he is equal to the first ruler then we have processed everyone in the family and we terminate the while loop.
while (true)
{
...
if (family[curr_ruler_idx].has_child)
{
...
}
else
{
if (family[curr_ruler_idx].sibling != nullptr)
{
...
}
else
{
while (curr_ruler_idx != first_ruler_idx &&
family[curr_ruler_idx].parent->sibling == nullptr)
{
curr_ruler_idx = family[curr_ruler_idx].parent->index;
}
if (curr_ruler_idx == first_ruler_idx)
{
break;
}
if (family[curr_ruler_idx].parent->sibling != nullptr)
{
curr_ruler_idx = family[curr_ruler_idx].parent->sibling->index;
}
}
}
map_parent_children(family, curr_ruler_idx);
}
In while loop we again call map_parent_children
function because curr_ruler_idx
is changed.
Function map_parent_children :
In this function, we have passed a vector of Details
family
and an integer variable curr_ruler_idx
as parameter.
This function will map the ruler at curr_ruler_idx
with his/her children.
First we declare a vector of integers next_gen_m_idx
which will store the indices of male children of the ruler at curr_ruler_idx
.
And vector of integers next_gen_f_idx
will store the indices of female children of the ruler at curr_ruler_idx
.
std::vector<int> next_gen_m_idx; // stores index of male members of next generation
std::vector<int> next_gen_f_idx; // stores index of female members of next generation
We will iterate through the vector family
and if the name of the parent of the person at the current index is equal to the name of the ruler at curr_ruler_idx
then the current ruler is the parent of the person in process. Then we will enter the index of the current person in vector next_gen_m_idx
or next_gen_f_idx
according to its gender.
for (int i = 0; i < family.size(); ++i)
{
if (family[i].parent_name == family[curr_ruler_idx].name)
{
family[curr_ruler_idx].has_child = true;
family[i].parent = &family[curr_ruler_idx]; // mapping parent
if (family[i].gender == "M")
{
next_gen_m_idx.push_back(i);
}
else
{
next_gen_f_idx.push_back(i);
}
}
}
In siblings, the eldest sibling is the next ruler. So we will sort both vectors next_gen_m_idx
and next_gen_f_idx
according to there age. And then we will call function map_siblings
.
//sort both vectors according to age
if (family[curr_ruler_idx].has_child)
{
static const auto by_age = [family](const int i, const int j)
{
return family[i].birth < family[j].birth; // year of birth is smaller means age is bigger
};
std::sort(next_gen_m_idx.begin(), next_gen_m_idx.begin(), by_age);
std::sort(next_gen_f_idx.begin(), next_gen_f_idx.begin(), by_age);
map_siblings(next_gen_m_idx, next_gen_f_idx, family, curr_ruler_idx);
}
Function map_siblings :
In this function two integer vectors male_idx
and female_idx
, one vector of Details family
and an integer variable curr_ruler_idx
are passed as parameters.
The vectors male_idx
and female_idx
are already sorted according to ages. We need to form links between siblings.
First we will check whether the vector male_idx
is empty of not. If it is not empty then the first_child
of current ruler is set to the child at the index 0
of vector male_idx
.
Then if the size of male_idx
is 1 and vector female_idx
is not empty then the sibling of child at index 0
of male_idx
is child at the index 0
of vector female_idx
.
Otherwise we will iterate through vector male_idx
and link siblings
if (!male_idx.empty())
{
family[curr_ruler_idx].first_child = &family[male_idx[0]];
if (male_idx.size() == 1)
{
if (!female_idx.empty())
{
family[male_idx[0]].sibling = &family[female_idx[0]];
}
}
else
{
for (int i = 0; i < male_idx.size()-1; ++i)
{
family[male_idx[i]].sibling = &family[male_idx[i+1]];
}
}
}
else
{
...
}
If vector male_idx
is empty then first child of current ruler is the child at index 0
of vector female_idx
.
if (!male_idx.empty())
{
...
}
else
{
family[curr_ruler_idx].first_child = &family[female_idx[0]];
}
Now we will link last male child to the first female child, if number of male children is more than 1 and there is aleast one female child.
if (!female_idx.empty())
{
if (male_idx.size() > 1)
{
family[male_idx.back()].sibling = &family[female_idx[0]];
}
if (female_idx.size() > 1)
{
for (int i = 0; i < female_idx.size()-1; ++i)
{
family[female_idx[i]].sibling = &family[female_idx[i+1]];
}
}
}
C++ Implementation
For complete code visit : Programmercave
Note : One test case is not passed
View this on Github
If you have another solution then please share it in the comments below.
Other Competitive Programming Problems and Solutions
Stock Exchange Losses — CodinGame
Dungeons and Maps — CodinGame
Originally published at https://programmercave.com/ on April 11, 2021.