Subset Sum, with backtracking and classes - c++

Given a sequence of integers and a number, the program must say if there's any cobination in that sequence that sums the number. For example:
Input: 1 2 3 4 5 # 6
Output: true (because 1+5 = 6, or 2 + 4 = 6, or 1 + 2 + 3 = 6).
It doesn't matter what solution it finds, only if there's a solution.
For input: 1 2 3 4 5 # 100
Output: false. None of the combination of that numbers sums 100.
Now, for input:
243 5 35 24 412 325 346 24 243 432 # 1000
I'm getting
main: malloc.c:2401: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
When it's suppose to say false.
I must use 3 classes. Solver, solution and candidat.
Solver just calls the backtracking method.
Solution has a possible solution.
Candidat has the indeix of the number of the sequence which is being looked.
I don't understand how to use the integer _lvl of Solution class to move around the different candidates.
Class Solver is correct. The error must be in solution class and candidats.
My question is, how must I use candidats and _lvl to check the possible solutions?
How should I implement the following methods in solution class?:
Acceptable, complet, anotate, desanotate.
Im getting wrong answers and out_of_ranges errors.
class solver
{
public:
solver();
bool solve(const solution &initial);
solucio getSolution() const;
private:
void findASolution();
bool _found;
solution _sol;
};
solver.cpp
bool solver::solve(const solution &initial)
{
_found = false;
_sol = initial;
findASolution();
return (_found);
}
void solver::findASolution()
{
candidat iCan = _sol.inicializateCandidats();
while ((not iCan.isEnd()) and (!_found))
{
if (_sol.acceptable(iCan)) {
_sol.anotate(iCan);
if(not _sol.complet()) {
findASolution();
if (!_found) {
_sol.desanotate(iCan);
}
}
else {
_found = true;
}
}
iCan.next();
}
}
This class is supposed to be correct. Im having trouble with classes solution and candidat. Class solution have 5 important methods: Acceptable, Complet, inicializateCandidates(), anotate and desanotate.
Acceptable is true if a candidate can be part of the solution.
Complet if a solution is found.
Anotate to save the possible candidates.
Desanotate to remove candidates that no long can be part of the solution.
inicializateCandidates invoces the candidats constructor.
solution();
solution(const int sequence[], const int &n, const int &sum) {
_searchedSum = sum;
_n = n;
_sum = 0;
_lvl = 0;
reserve(); // bad_alloc. Makes space for vectors
for (int i = 0; i < n; i++) {
_sequence[i] = sequence[i];
_candidates[i] = - 1;
}
solution(const solution &o);
~solution();
solution & operator=(const solution &o);
candidat inicializateCandidats() const {
return candidat(_n);
}
bool acceptable(const candidat &iCan) const {
return (_sum + _sequence[iCan.actual()] <= _searchedSum);
}
bool complet() const {
return (_sum == _searchedSum);
}
void show() const;
void anotate(const candidat &iCan) {
_niv++;
_candidates[_niv] = iCan.actual();
_sum += _sequence[iCan.actual()];
}
void desanotate(const candidat &iCan) {
_candidates[_niv] = - 1;
_sum -= _sequence[iCan.actual()];
_niv--;
}
private:
// memory gestion methods
void solution::reserve() {
_sequence = new int[_n];
_candidates = new int[_n];
}
int *_sequence; // original sequence
int *_candidates; // possible subsequence part of solution
int _n; // size of the array
int _lvl; // lvl of the tree generated by backtracking
int _searchedSum;
int _sum; // total sum of actual solution
And class candidat, which is just a counter. Nothing else.
candidat::candidat(const int &n) {
_size = n;
_iCan = 0;
}
bool candidat::isEnd() const {
return (_iCan >= _size);
}
int candidat::actual() const {
if (esEnd()) {
throw ("No more candidates");
}
return _iCan;
}
void candidat::next() {
if (esFi()) {
throw ("No more candidates");
}
_iCan++;
}

I've found a possible solution but it does not fit the requirements at all.
In class solver, I create an attribute to save anterior candidate, inicializate at -1.
The constructor of candidat class changes at this way:
candidat::candidat(const int &n, const int &ant) {
_size = n;
_iCan = ant + 1;
}
In solution.h now there is a boolean array to save the candidates that can be part of the solution. _lvl is eliminated.
In solver.cpp, the backtracking changes a little, but it shouldn't be changed.
bool solver::solve(const solution &initial) {
_found = false;
_ant = -1;
_sol = initial;
findASolution();
return (_found);
}
void solver::findASolution() {
**candidat iCan = _sol.inicializateCandidats(_ant);**
while ((not iCan.isEnd()) and (!_found))
{
if (_sol.acceptable(iCan)) {
_sol.anotate(iCan);
if(not _sol.complet()) {
**_ant = iCan.actual();**
findASolution();
if (!_found) {
_sol.desanotate(iCan);
}
}
else {
_found = true;
}
}
iCan.next();
}
}
Differences remarked.
But this is not the best solution. The correct solution should be using _lvl attribute. The solver class shouldn't know aything about the attributes of solution. Just if it's found or not.

Related

Displaying steps to maximum profit

I am passing in a sorted vector that contains a data as such:
Job Details {Start Time, Finish Time, Profit}
Job 1: {1 , 2 , 50 }
Job 2: {3 , 5 , 20 }
Job 3: {6 , 19 , 100 }
Job 4: {2 , 100 , 200 }
The code finds which jobs are the best for profit by checking all paths that don't overlap for example job 1,2,3 or job 1,4 are possible and it determines job 1,4 is the best value. I am trying to build a function that displays the path on how the code got to the best possible solution.
Ex. Job 1 --> Job 4 --> $250.
But am lost on the implementation.
Main.cpp
// Find the latest job (in sorted array) that doesn't
// conflict with the job[i]. If there is no compatible job,
// then it returns -1.
int latestNonConflict(vector<Task>someVector, int i)
{
for (int j = i - 1; j >= 0; j--)
{
if (someVector[j].getEndTime() <= someVector[i - 1].getStartTime())
{
return j;
}
}
return -1;
}
// A recursive function that returns the maximum possible
// profit from given array of jobs. The array of jobs must
// be sorted according to finish time.
int bruteForceMethod(vector<Task>someVector, int n)
{
// Base case
if (n == 1)
{
return someVector[n - 1].getValue();
}
// Find profit when current job is inclueded
int inclProf = someVector[n - 1].getValue();
int i = latestNonConflict(someVector, n);
if (i != -1)
cout << someVector[i].getLabel() << "-->";
inclProf += bruteForceMethod(someVector, i + 1);
// Find profit when current job is excluded
int exclProf = bruteForceMethod(someVector, n - 1);
return max(inclProf, exclProf);
}
// The main function that returns the maximum possible
// profit from given array of jobs
int findMaxProfit(vector<Task>someVector, int n)
{
return bruteForceMethod(someVector, n);
}
int main()
{
cout << "The optimal profit is " << bruteForceMethod(tasksVector,
tasksVector.size()) << endl;
return 0;
}
Task.h
#include <string>
using namespace std;
#ifndef Task_h
#define Task_h
class Task
{
public:
Task();
Task(string, int, int, int);
void setLabel(string);
string getLabel();
void setStartTime(int);
int getStartTime();
void setEndTime(int);
int getEndTime();
void setValue(int);
int getValue();
private:
string label;
int startTime;
int endTime;
int value;
};
#endif
Task.cpp
#include "Task.h"
Task::Task()
{
}
Task::Task(string inLabel, int inStartTime, int inEndTime, int inValue)
{
label = inLabel;
startTime = inStartTime;
endTime = inEndTime;
value = inValue;
}
void Task::setLabel(string inLabel)
{
label = inLabel;
}
string Task::getLabel()
{
return label;
}
void Task::setStartTime(int inStartTime)
{
startTime = inStartTime;
}
int Task::getStartTime()
{
return startTime;
}
void Task::setEndTime(int inEndTime)
{
endTime = inEndTime;
}
int Task::getEndTime()
{
return endTime;
}
void Task::setValue(int inValue)
{
value = inValue;
}
int Task::getValue()
{
return value;
}
You can simply consider a weighted graph G where
a node is a job
a node A is linked to a node B if A.endTime < B.startTime
weight of edge(A,B) is B.profit (taking the path to B means doing job B)
You want to get the path of maximal weight of G.
Usually algorithm want a function to minimize so instead lets take for weight -B.profit.
We can always cite the Floyd–Warshall algorithm , there is even the path reconstruction algorithm provided in link aforementionned.
Home made
But let's do it home-made since it seems to be some homework.
You can do it the bruteforce way (which is less efficient but easier to grasp than Floyd Warshall) and check all the longest paths...
create a root node to which you add for children all the jobs with their respective weight associated then consider the recursive function:
def get_longest_path(node):
if !node.children
return 0
best_all = {
w: weight(node, node.children[0]),
path: [node, get_longest_path(node.children[0])]
}
for node.children as child //starting from 1
best_path_i = get_longest_path(child)
//if we found a path with lower total weight (that is, with maximal profit)
if best_path_i != 0 && best_path_i.weight < best_all.weight
best_all = {
w: weight(node, child),
path:[node, best_path_i]
}
return best_all
get_longest_path(root)
note that you can trivially memoize get_longest_path (to avoid reevalution for an already visited node) without much burden
cache = {}
def get_longest_path(node):
if !node.children
return 0
//node.id is jobId
if node.id in cache
return cache[node.id]
best_all = {
w: weight(node,node.children[0]),
path: [node, get_longest_path(node.children[0])]
}
for node.children as child //starting from 1
best_path_i = get_longest_path(child)
//if we found a path with lower total weight (that is, with maximal profit)
if best_path_i != 0 && best_path_i.weight < best_all.weight
best_all = {
w: weight(node, child),
path:[node, best_path_i]
}
cache[node.id] = best_all
return best_all
get_longest_path(root)
No cycles handled but you don't have a job which reverses time I guess
This algorithm can be approached very similarly to a recursive permutation implementation of say a string ABC which produces ABC, ACB, BAC, BCA, CAB, CBA.
Here is a simple demonstration
You could modify this to "prune" the tree when a condition is not met (eg. the letter after is lower in the alphabet than the previous), so you would get ABC as it is the only one where every succesive letter is lower (A<B<C).
Once you have that, you now understand how to recurse over Task's and prune when comparing the startTime and endTime of jobs...
So here is an implementation of the above in C++:
#include <iostream>
#include <vector>
using namespace std;
struct Task {
// global counter tracking how many instances
static int counter;
int startTime;
int endTime;
int value;
int label;
Task(int inStartTime, int inEndTime, int inValue) {
startTime = inStartTime;
endTime = inEndTime;
value = inValue;
label = Task::counter++;
}
};
// store an index to each Task to keep track
int Task::counter = 1;
// build a search tree of all possible Task sequences
// pruning if next Task and current Task overlap
void jobSearchTree(vector<Task> jobSequence,
vector<Task> possibleJobs,
vector<vector<Task>> &possibleJobSequences) {
for (int i = 0; i < possibleJobs.size(); i++) {
vector<Task> l;
for (int j = 0; j < jobSequence.size(); j++)
{
l.push_back(jobSequence.at(j));
}
l.push_back(possibleJobs[i]);
// initial recursive call
if (!jobSequence.size()) {
vector<Task> searchJobs(possibleJobs);
searchJobs.erase(searchJobs.begin() + i);
jobSearchTree(l, searchJobs, possibleJobSequences);
}
// test if jobs occur sequentially
else if (l.at(l.size()-2).endTime <= l.at(l.size()-1).startTime) {
// add the Task sequence
possibleJobSequences.push_back(l);
vector<Task> searchJobs(possibleJobs);
// remove this Task from the search
searchJobs.erase(searchJobs.begin() + i);
// recursive call with Task sequence as the head
// and the remaining possible jobs as the tail
jobSearchTree(l, searchJobs, possibleJobSequences);
}
}
}
vector<int> getBestJobSequence(vector<vector<Task>> possibleJobSequences) {
int maxProfit = 0;
int totalProfit = 0;
vector<Task> bestJobSequence;
for (auto jobSequence : possibleJobSequences) {
totalProfit = 0;
for (auto Task : jobSequence) {
totalProfit += Task.value;
}
if (totalProfit > maxProfit) {
maxProfit = totalProfit;
bestJobSequence = jobSequence;
}
}
vector<int> jobIds;
for (auto Task : bestJobSequence) {
jobIds.push_back(Task.label);
}
return jobIds;
}
int main()
{
Task s1(1, 2, 50);
Task s2(3, 5, 20);
Task s3(6, 19, 100);
Task s4(2, 100, 200);
vector<Task> allJobs = {s1, s3, s4};
vector<vector<Task>> possibleJobSequences;
vector<Task> currentJobSequence;
jobSearchTree(currentJobSequence, allJobs, possibleJobSequences);
vector<int> bestJobSequence = getBestJobSequence(possibleJobSequences);
for (auto job : bestJobSequence) {
cout << job << endl;
}
return 0;
}

Problem to acces a position in an list c++

I'm implementing a function to insert a set of nodes in a set of routes. This function is described as follows:
void Repair_ChooseARouteAndAPositionRandomly (SOLUTION &sol, vector<int> &NodesPscine, vector<int>&RoutesPscine, DATA data, int max_slot){
while (NodesPscine.size() != 0) {
int aux;
int pairpos;
int pairRoute;
int pairNode;
list<VEHICLE>:: iterator irouteit;
vector<bool> RotaJaFoiSorteada = vector<bool>(sol.SetP.size(),false);
pairpos = rand() % NodesPscine.size();
pairNode = NodesPscine[pairpos];
pairRoute = RoutesPscine[pairpos];
bool sorteaDenovo = true;
while (sorteaDenovo == true) {
bool rotaJafoiSorteada = false;
while (rotaJafoiSorteada == false) {
aux = rand() % sol.SetP.size();
if (RotaJaFoiSorteada[aux] == false) {
irouteit = next(sol.SetP.begin(), aux);
rotaJafoiSorteada = true;
RotaJaFoiSorteada[aux] = true;
}
}
bool NoJaExisteNaRota = false;
list<int>:: iterator ii;
for (ii = irouteit->rotaVehicle.begin(); ii != irouteit->rotaVehicle.end(); ii++) {
if (pairNode == *ii) {
NoJaExisteNaRota = true;
break;
}
}
if (NoJaExisteNaRota == false) {
double melhorDur = 0;
list <int>::iterator melhorPos = irouteit->rotaVehicle.begin();
double NovaDur;
InsereNaPosicaoMaisBarata (irouteit->rotaVehicle, irouteit->type, pairNode, data, melhorDur, melhorPos);
NovaDur = irouteit->duracaoTotal + melhorDur;
if (NovaDur <= max_slot) {
irouteit->rotaVehicle.insert(melhorPos,pairNode);
irouteit->duracaoTotal = NovaDur;
int cont = 0;
list<int>::iterator itprim = irouteit->rotaVehicle.begin();
list<int>::iterator itseg;
irouteit->distanceTotal = 0;
while (cont < irouteit->rotaVehicle.size()-1) {
itseg = next(itprim, 1);
irouteit->distanceTotal += data.dist[*itprim][*itseg];
++itprim;
++cont;
}
sorteaDenovo = false;
NodesPscine.erase(NodesPscine.begin()+pairpos);
RoutesPscine.erase(RoutesPscine.begin()+pairpos);
} // if (NovaDur <= max_slot) {
} // if (NoJaExisteNaRota == false) {
} // while (sorteaDenovo == true) {
} // while (NodesPscine.size() != 0) {
}
I also describe another function and some structs that may be important to identify my mistake.
void InsereNaPosicaoMaisBarata (list<int> Rota, int vehicle, int no, DATA data, double &melhorDur, list <int>::iterator &melhorPos ) {
list <int>:: iterator itprim = Rota.begin();
list <int>:: iterator itseg;
int cont = 0;
melhorDur = 10000000000000000;
while (cont < (Rota.size()-1)) {
itseg = next(itprim, 1);
double aux = data.l[vehicle][*itprim][no] + data.l[vehicle][no][*itseg] - data.l[vehicle][*itprim][*itseg];
if (melhorDur > aux) {
melhorDur = aux;
melhorPos = itseg;
}
++itprim;
++cont;
}
}
struct VEHICLE {
int type;
int idx;
double custo;
double distanceTotal;
double duracaoTotal;
list<int> rotaVehicle;
};
struct SOLUTION {
list<VEHICLE> SetP;
};
Everything goes fine to insert the first pairNode randomly chosen. However, when a second pairNode is chosen, the program runs until the line just after calling the function InsereNaPosicaoMaisBarata. If I put any cout inside this function, it does not appear. I think the problem is in the line "irouteit->rotaVehicle.insert(melhorPos,pairNode);", because when I comment it, the code runs until the end.
If I have, for example, these routes:
route 1 { 4 2 1 3 4 }
route 2 { 3 2 4 3 }
route 3 { 4 2 1 3 4 }
route 4 {4 1 3 4 }
route 5 { 2 4 2 }
route 6 { 3 2 4 3 }
If we have the nodes to be inserted in any of these routes as NodesPscine = {3,2}. If node 3 is randomly chosen to be inserted in route 5, it works well.
After, node 4 is chosen to be inserted in route 4. Then, the program runs until the function InsereNaPosicaoMaisBarata and the error message appears:
*** Error in `./heuristica': malloc(): memory corruption (fast): 0x00000000035d0680 ***
I suppose the way I'm identifying the melhorPos is not okay. But I can't figure out what is wrong.
You did not post all of your code, but one obvious mistake is this:
InsereNaPosicaoMaisBarata (irouteit->rotaVehicle, // <-- This parameter
irouteit->type,
pairNode,
data,
melhorDur,
melhorPos);
Your function is declared as this:
void InsereNaPosicaoMaisBarata (list<int> Rota, // <-- passed by value
int vehicle,
int no,
DATA data,
double &melhorDur,
list <int>::iterator &melhorPos )
Then inside the function, you do this:
list <int>:: iterator itprim = Rota.begin(); // <-- This is a local std::list
list <int>:: iterator itseg;
//...
itseg = next(itprim, 1);
//...
melhorPos = itseg; // <-- This is now referencing a local std::list entry
On return, you then use the last parameter:
irouteit->rotaVehicle.insert(melhorPos,pairNode); // <-- Trouble
The problem with all of this is that the first parameter (Rota) is passed by value. That means the function InsereNaPosicaMaisBarata is working with a temporary std::list.
You then set melhorPos to point to an entry into the temporary list. The problem is that on return, Rota has been destroyed, and you now have an invalid iterator being used on the return.
The solution is to change the function to have the first parameter as a reference:
void InsereNaPosicaoMaisBarata (list<int>& Rota, // <-- passed by reference
int vehicle,
int no,
DATA data,
double &melhorDur,
list <int>::iterator &melhorPos )

A* Performance at large maps

i would like some help for my AStar algorithm search, which takes from my point of view far to long. Even though my map is with 500 * 400 coordinates(objectively is my tile graph a bit smaller since I don't took the walls into the TileGraph.) large, I would like to expect the result after a few seconds. The world looks like this, despite the task not being mine
I want to search from marked coordinates "Start"(120|180) to "Ziel"(320|220), which currently takes 48 minutes. And sorry for all, who don't speak german, but the text at the picture isn't important.
At first I want to show you, what I've programmed for A*. In General adapted myself to the pseudocode at https://en.wikipedia.org/wiki/A*_search_algorithm .
bool AStarPath::Processing(Node* Start, Node* End)
m_Start = Start;
m_End = End;
for (Node* n : m_SearchRoom->GetAllNodes())
{
DistanceToStart[n] = std::numeric_limits<float>::infinity();
CameFrom[n] = nullptr;
}
DistanceToStart[m_Start] = 0;
NotEvaluatedNodes.AddElement(0, m_Start);
while (NotEvaluatedNodes.IsEmpty() == false)
{
Node* currentNode = NotEvaluatedNodes.GetElement();
NotEvaluatedNodes.DeleteElement();
if (currentNode == m_End)
{
ReconstructPath();
return true;
}
EvaluatedNodes.insert(currentNode);
ExamineNeighbours(currentNode);
}
return false;
//End Processing
void AStarPath::ExamineNeighbours(Node* current)
for (Node* neighbour : m_SearchRoom->GetNeighbours(current))
{
if (std::find(EvaluatedNodes.begin(), EvaluatedNodes.end(), neighbour) != EvaluatedNodes.end())
{
continue;
}
bool InOpenSet = NotEvaluatedNodes.ContainsElement(neighbour);
float tentative_g_score = DistanceToStart[current] + DistanceBetween(current, neighbour);
if (InOpenSet == true && tentative_g_score >= DistanceToStart[neighbour])
{
continue;
}
CameFrom[neighbour] = current;
DistanceToStart[neighbour] = tentative_g_score;
float Valuation = tentative_g_score + DistanceBetween(neighbour, m_End);
if (InOpenSet == false)
{
NotEvaluatedNodes.AddElement(Valuation, neighbour);
}
else
{
NotEvaluatedNodes.UpdatePriority(neighbour, Valuation);
}
}
//END ExamineNeighbours
double AStarPath::DistanceBetween(Node* a, Node* b)
return sqrt(pow(m_SearchRoom->GetNodeX(a) - m_SearchRoom->GetNodeX(b), 2)
+ pow(m_SearchRoom->GetNodeY(a) - m_SearchRoom->GetNodeY(b), 2));
//END DistanceBetween
I'm sorry for the bad formatting, but I don't really know how to work with the code blocks here.
class AStarPath
private:
std::unordered_set<Node*> EvaluatedNodes;
Binary_Heap NotEvaluatedNodes;
std::unordered_map<Node*, float> DistanceToStart;
std::unordered_map<Node*, Node*> CameFrom;
std::vector<Node*> m_path;
TileGraph* m_SearchRoom;
//END Class AStarPath
Anyway, i have thought myself over my problem already and changed some things.
Firstly, I implemented a binary heap instead of the std::priority_queue. I used a page at policyalmanac for it, but I'm not permitted to add another link, so I can't really give you the address. It improved the performance, but it still takes quite long as I told at the beginning.
Secondly, I used unordered containers (if there are two options), so that the containers don't have to be sorted after the changes. For my EvaluatedNodes I took the std::unordered_set, since from my knowledge it's fastest for std::find, which I use for containment checks.
The usage of std::unordered_map is caused by the need of having seperate keys and values.
Thirdly, I thought about splitting my map into nodes, which represent multiple coordinates(instead of now where one node represents one coordinate) , but I'm not really sure how to choose them. I thought about setting points at position, that the algorithm decises based on the length and width of the map and add neighbouring coordinates, if there aren't a specific distance or more away from the base node/coordinate and I can reach them only from previous added coordinates. To Check whether there is a ability to walk, I would have used the regular A*, with only the coordinates(converted to A* nodes), which are in these big nodes. Despite this I'm unsure which coordinates I should take for the start and end of this pathfinding. This would probably reduce the number of nodes/coordinates, which are checked, if I only use the coordinates/nodes, which were part of the big nodes.(So that only nodes are used, which where part of the bigger nodes at an upper level)
I'm sorry for my english, but hope that all will be understandable. I'm looking forward to your answers and learning new techniques and ways to handle problems and as well learn about all the hundreds of stupids mistakes I produced.
If any important aspect is unclear or if I should add more code/information, feel free to ask.
EDIT: Binary_Heap
class Binary_Heap
private:
std::vector<int> Index;
std::vector<int> m_Valuation;
std::vector<Node*> elements;
int NodesChecked;
int m_NumberOfHeapItems;
void TryToMoveElementUp(int i_pos);
void TryToMoveElementDown(int i_pos);
public:
Binary_Heap(int i_numberOfElements);
void AddElement(int Valuation, Node* element);
void DeleteElement();
Node* GetElement();
bool IsEmpty();
bool ContainsElement(Node* i_node);
void UpdatePriority(Node* i_node, float newValuation);
Binary_Heap::Binary_Heap(int i_numberOfElements)
Index.resize(i_numberOfElements);
elements.resize(i_numberOfElements);
m_Valuation.resize(i_numberOfElements);
NodesChecked = 0;
m_NumberOfHeapItems = 0;
void Binary_Heap::AddElement(int valuation, Node* element)
++NodesChecked;
++m_NumberOfHeapItems;
Index[m_NumberOfHeapItems] = NodesChecked;
m_Valuation[NodesChecked] = valuation;
elements[NodesChecked] = element;
TryToMoveElementUp(m_NumberOfHeapItems);
void Binary_Heap::DeleteElement()
elements[Index[1]] = nullptr;
m_Valuation[Index[1]] = 0;
Index[1] = Index[m_NumberOfHeapItems];
--m_NumberOfHeapItems;
TryToMoveElementDown(1);
bool Binary_Heap::IsEmpty()
return m_NumberOfHeapItems == 0;
Node* Binary_Heap::GetElement()
return elements[Index[1]];
bool Binary_Heap::ContainsElement(Node* i_element)
return std::find(elements.begin(), elements.end(), i_element) != elements.end();
void Binary_Heap::UpdatePriority(Node* i_node, float newValuation)
if (ContainsElement(i_node) == false)
{
AddElement(newValuation, i_node);
}
else
{
int treePosition;
for (int i = 1; i < Index.size(); i++)
{
if (elements[Index[i]] == i_node)
{
treePosition = i;
break;
}
}
//Won't influence each other, since only one of them will change the position
TryToMoveElementUp(treePosition);
TryToMoveElementDown(treePosition);
}
void Binary_Heap::TryToMoveElementDown(int i_pos)
int nextPosition = i_pos;
while (true)
{
int currentPosition = nextPosition;
if (2 * currentPosition + 1 <= m_NumberOfHeapItems)
{
if (m_Valuation[Index[currentPosition]] >= m_Valuation[Index[2 * currentPosition]])
{
nextPosition = 2 * currentPosition;
}
if (m_Valuation[Index[currentPosition]] >= m_Valuation[Index[2 * currentPosition + 1]])
{
nextPosition = 2 * currentPosition + 1;
}
}
else
{
if (2 * currentPosition <= m_NumberOfHeapItems)
{
if (m_Valuation[Index[currentPosition]] >= m_Valuation[Index[2 * currentPosition]])
{
nextPosition = 2 * currentPosition;
}
}
}
if (currentPosition != nextPosition)
{
int tmp = Index[currentPosition];
Index[currentPosition] = Index[nextPosition];
Index[nextPosition] = tmp;
}
else
{
break;
}
}
void Binary_Heap::TryToMoveElementUp(int i_pos)
int treePosition = i_pos;
while (treePosition != 1)
{
if (m_Valuation[Index[treePosition]] <= m_Valuation[Index[treePosition / 2]])
{
int tmp = Index[treePosition / 2];
Index[treePosition / 2] = Index[treePosition];
Index[treePosition] = tmp;
treePosition = treePosition / 2;
}
else
{
break;
}
}
This line introduces major inefficiency, as it needs to iterate over all the nodes in the queue, in each iteration.
bool InOpenSet = NotEvaluatedNodes.ContainsElement(neighbour);
Try using a more efficient data structure, e.g. the unordered_set you use for EvaluatedNodes. Whenever you push or pop a node from the heap, modify the set accordingly to always contain only the nodes in the heap.

How to limit a decrement?

There is a initial game difficulty which is
game_difficulty=5 //Initial
Every 3 times if you get it right, your difficulty goes up to infinity but every 3 times you get it wrong, your difficulty goes down but not below 5. So, in this code for ex:
if(user_words==words) win_count+=1;
else() incorrect_count+=1;
if(win_count%3==0) /*increase diff*/;
if(incorrect_count%3==0) /*decrease difficulty*/;
How should I go about doing this?
Simple answer:
if(incorrect_count%3==0) difficulty = max(difficulty-1, 5);
But personally I would wrap it up in a small class then you can contain all the logic and expand it as you go along, something such as:
class Difficulty
{
public:
Difficulty() {};
void AddWin()
{
m_IncorrectCount = 0; // reset because we got one right?
if (++m_WinCount % 3)
{
m_WinCount = 0;
++m_CurrentDifficulty;
}
}
void AddIncorrect()
{
m_WinCount = 0; // reset because we got one wrong?
if (++m_IncorrectCount >= 3 && m_CurrentDifficulty > 5)
{
m_IncorrectCount = 0;
--m_CurrentDifficulty;
}
}
int GetDifficulty()
{
return m_CurrentDifficulty;
}
private:
int m_CurrentDifficulty = 5;
int m_WinCount = 0;
int m_IncorrectCount = 0;
};
You could just add this as a condition:
if (user words==words) {
win_count += 1;
if (win_count %3 == 0) {
++diff;
}
} else {
incorrect_count += 1;
if (incorrect_count % 3 == 0 && diff > 5) {
--diff
}
}
For example:
if(win_count%3==0) difficulty++;
if(incorrect_count%3==0 && difficulty > 5) difficulty--;
This can be turned into a motivating example for custom data types.
Create a class which wraps the difficulty int as a private member variable, and in the public member functions make sure that the so-called contract is met. You will end up with a value which is always guaranteed to meet your specifications. Here is an example:
class Difficulty
{
public:
// initial values for a new Difficulty object:
Difficulty() :
right_answer_count(0),
wrong_answer_count(0),
value(5)
{}
// called when a right answer should be taken into account:
void GotItRight()
{
++right_answer_count;
if (right_answer_count == 3)
{
right_answer_count = 0;
++value;
}
}
// called when a wrong answer should be taken into account:
void GotItWrong()
{
++wrong_answer_count;
if (wrong_answer_count == 3)
{
wrong_answer_count = 0;
--value;
if (value < 5)
{
value = 5;
}
}
}
// returns the value itself
int Value() const
{
return value;
}
private:
int right_answer_count;
int wrong_answer_count;
int value;
};
And here is how you would use the class:
Difficulty game_difficulty;
// six right answers:
for (int count = 0; count < 6; ++count)
{
game_difficulty.GotItRight();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
// three wrong answers:
for (int count = 0; count < 3; ++count)
{
game_difficulty.GotItWrong();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
// one hundred wrong answers:
for (int count = 0; count < 100; ++count)
{
game_difficulty.GotItWrong();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
Output:
7
6
5
Once you have a firm grasp on how such types are created and used, you can start to look into operator overloading so that the type can be used more like a real int, i.e. with +, - and so on.
How should I go about doing this?
You have marked this question as C++. IMHO the c++ way is to create a class encapsulating all your issues.
Perhaps something like:
class GameDifficulty
{
public:
GameDifficulty () :
game_difficulty (5), win_count(0), incorrect_count(0)
{}
~GameDifficulty () {}
void update(const T& words)
{
if(user words==words) win_count+=1;
else incorrect_count+=1;
// modify game_difficulty as you desire
if(win_count%3 == 0)
game_difficulty += 1 ; // increase diff no upper limit
if((incorrect_count%3 == 0) && (game_difficulty > 5))
game_difficulty -= 1; //decrease diff;
}
inline int gameDifficulty() { return (game_difficulty); }
// and any other access per needs of your game
private:
int game_difficulty;
int win_count;
int incorrect_count;
}
// note - not compiled or tested
usage would be:
// instantiate
GameDiffculty gameDifficulty;
// ...
// use update()
gameDifficulty.update(word);
// ...
// use access
gameDifficulty.gameDifficulty();
Advantage: encapsulation
This code is in one place, not polluting elsewhere in your code.
You can change these policies in this one place, with no impact to the rest of your code.

Is there any functional difference between the following 2 code snippets?

Is there any functional difference between the following 2 code snippets?
bool ColorClass::setTo(int inRed, int inGreen, int inBlue)
{
amountRed = inRed;
amountGreen = inGreen;
amountBlue = inBlue;
return clipColor(amountRed, amountGreen, amountBlue);
}
bool ColorClass::setTo(int inRed, int inGreen, int inBlue)
{
amountRed = inRed;
amountGreen = inGreen;
amountBlue = inBlue;
if (clipColor(amountRed, amountGreen, amountBlue))
{
return true;
}
else
{
return false;
}
}
The functions the above code calls are defined below:
bool ColorClass::clipColor(int &checkRed, int &checkGreen, int &checkBlue)
{
int numClips = 0; //numClips is used to counter number of clips made
checkColorBounds(checkRed, numClips);
checkColorBounds(checkGreen, numClips );
checkColorBounds(checkBlue, numClips);
return (numClips != 0);
}
void ColorClass::checkColorBounds(int &color, int &clipCounter)
{
if(color > MAXCOLOR)
{
color = MAXCOLOR;
clipCounter++;
}
else if (color < MINCOLOR)
{
color = MINCOLOR;
clipCounter ++;
}
}
I tested both and gone through both, and I can't seem to notice anything functionally different.
I like the first one better, because it is much more succint and more efficient (avoids the if-else)
There're no any functional differences at all. Then use the 1st one.
KISS