I'm trying to write a method that would find the shortest path length from one vertex to another, using Dijkstra algorithm. But it doesn't give a correct output. Could you give some advice as to where the problem is?
unsigned distDIJKSTRA(unsigned vert1, unsigned vert2)
{
vector<Vertex3*> pq;
Vertex3* v;
unsigned distance = UINT_MAX;
for (unsigned i = 0; i < vertices.size(); i++)
{
if (vertices[i]->value == vert1)
v = new Vertex3(vertices[i], 0);
else
v = new Vertex3(vertices[i], distance);
pq.push_back(v);
}
make_heap(pq.begin(), pq.end(), lowerPrior);
unsigned newDist;
while (!pq.empty())
{
Vertex3* currV = pq.front();
// If the destination is reached
if (currV->vert->value == vert2)
return currV->dist;
pop_heap(pq.begin(), pq.end(), lowerPrior);
pq.pop_back();
// Checking if the route through currV is shorter
for (unsigned i = 0; i < currV->vert->adjList.size(); i++)
{
Vertex3* nextV = nullptr;
for (unsigned j = 0; j < pq.size(); j++)
if (pq[j]->vert == currV->vert->adjList[i]) {
nextV = pq[j];
break;
}
if (nextV != nullptr)
{
newDist = currV->dist + getWeight(currV->vert, nextV->vert);
if (newDist < nextV->dist)
nextV->dist = newDist;
}
else
continue;
}
sort_heap(pq.begin(), pq.end(), lowerPrior);
}
return UINT_MAX;
}
After updating the distances, your vector won't be a heap anymore. Further more, calling sort_heap in itself would also drop the heap property, instead of fixing it. (See http://en.cppreference.com/w/cpp/algorithm/sort_heap)
Call make_heap instead.
Also note the memory leak: you never deallocate the memory allocated for the Vertex3 objects.
Related
I have tried to solve the problem Rerouting at hacker rank. I am posting here for help as competition is over.
https://www.hackerrank.com/contests/hack-the-interview-v-asia-pacific/challenges/rerouting
I have tried to solve problem using Strong connected components, but test cases failed. I can understand we have to remove cycles. But I stuck how to approach problem. Below is solution i have written. I am looking for guidence how to move forward so that i can apply my knowledge future based on mistakes i made here. Thanks for your time and help
int getMinConnectionChange(vector<int> connection) {
// Idea: Get number of strongly connected components.
int numberOfVertices = connection.size();
for(int idx = 0; idx < numberOfVertices; idx++) {
cout << idx+1 <<":"<< connection[idx] << endl;
}
stack<int> stkVertices;
map<int, bool> mpVertexVisited; //is vertex visited.think this as a chalk mark for nodes visited.
int numOFSCCs = 0;
int currTime = 1;
for (int vertexId = 0; vertexId < numberOfVertices; vertexId++) {
// check if node is already visited.
if (mpVertexVisited.find(vertexId+1) == mpVertexVisited.end()) {
numOFSCCs++;
mpVertexVisited.insert(make_pair(vertexId+1, true));
stkVertices.push(vertexId+1);
currTime++;
while (!stkVertices.empty()) {
int iCurrentVertex = stkVertices.top();
stkVertices.pop();
// get adjacent vertices. In this excercise we have only one neighbour. i.e., edge
int neighbourVertexId = connection[iCurrentVertex-1];
// if vertex is already visisted, don't insert in to stack.
if (mpVertexVisited.find(neighbourVertexId) != mpVertexVisited.end()) {
continue;
}
mpVertexVisited.insert(make_pair(neighbourVertexId, true));
stkVertices.push(neighbourVertexId);
} // while loop
} // if condition m_mapVrtxTimes.find(*itr) == m_mapVrtxTimes.end()
} // for loop of vertices
return numOFSCCs - 1;
}
This is a problem that I just solved and would like to share the solution.
The problem can be solved with union-find.
Two main observation:
The number of edges that has to be changed is the number of components - 1 (not necessarily strongly connected) Thus, union-find is handy here for finding the number of components
Second observation is that some component doesn't have terminating node, consider 1<->2, in other words, a cycle exist. We can detect whether there exists a terminating node if some node doesn't have an outgoing edge.
If all components have a cycle, it means that we need to change every component instead of a number of components - 1. This is to make it such that the graph will have a terminating point.
Code:
struct UF {
vector<int> p, rank, size;
int cnt;
UF(int N) {
p = rank = size = vector<int>(N, 1);
for (int i = 0; i < N; i++) p[i] = i;
cnt = N;
}
int find(int i) {
return p[i] == i ? i : p[i] = find(p[i]);
}
bool connected(int i, int j) {
return find(i) == find(j);
}
void join(int i, int j) {
if (connected(i, j)) return;
int x = find(i), y = find(j);
cnt--;
if (rank[x] > rank[y]) {
p[y] = x;
size[x] += size[y];
} else {
p[x] = y;
size[y] += size[x];
if (rank[x] == rank[y]) rank[y]++;
}
}
};
int getMinConnectionChange(vector<int> connection) {
int nonCycle = 0;
int n = connection.size();
UF uf(n);
for(int i=0;i<n;i++) {
int to = connection[i] - 1;
if(to == i) nonCycle++;
else uf.join(i, to);
}
int components = uf.cnt;
int countCycle = uf.cnt - nonCycle;
int res = components - 1;
if(countCycle == components) res++; // all components have cycle
return res;
}
TL;DR: you can view this as looking for a minimal spanning arborescence problem.
More precisely, add a node for each server, and another one called "Terminate".
Make a complete graph (each node is linked to every other one) and set as cost 0 for the edges corresponding to your input, 1 for the other ones.
You can use for example Edmond's algorithm to solve this.
I've got a tree structure and a running example of how to iterate over it but as I'm a beginner when it comes to performance in coding, I wanted to ask if somebody knows a way to make it faster.
Eigen3 is used to build vectors.
The struct:
struct linkedBoxes{
std::vector<Vector3r> points;
std::vector<linkedBoxes*> boxes;
int sideLength;
};
And the algorithm:
std::vector<Vector3r> integPoints;
std::vector<linkedBoxes*> stack;
stack.push_back(firstBox);
vector<linkedBoxes*>::iterator iterator = stack.begin();
while (iterator != stack.end()){
if((*iterator)->boxes.size() == 0){
for (int j = 0; j < (*iterator)->points.size(); ++j) {
integPoints.push_back(point + (*iterator)->points[j]);
}
} else {
for (int k = 0; k < (*iterator)->points.size(); ++k) {
Vector3r tmpPoint = point + (*iterator)->points[k];
if(computeDistance(tmpPoint) < 0){
const size_t diff = iterator - stack.begin();
stack.push_back((*iterator)->boxes[k]);
iterator = stack.begin() + diff;
}
}
}
++iterator;
}
Point is a vector which is given to the function and computeDistance returns a value between -1 and 1.
Does somebody knows a way to make this faster?
Bruno
I am trying to create a maximum spanning tree in C++ but am having trouble preventing cycles. The code I have works alright for some cases, but for the majority of cases there is a cycle. I am using an adjacency matrix to find the edges.
double maximumST( vector< vector<double> > adjacencyMatrix ) {
const int size = adjacencyMatrix.size();
vector <double> edges;
int edgeCount = 0;
double value = 0;
std::vector<std::vector<int>> matrix(size, std::vector<int>(size));
for (int i = 0; i < size; i++) {
for (int j = i; j < size; j++) {
if (adjacencyMatrix[i][j] != 0) {
edges.push_back(adjacencyMatrix[i][j]);
matrix[i][j] = adjacencyMatrix[i][j];
edgeCount++;
}
}
}
sort(edges.begin(), edges.end(), std::greater<int>());
for (int i = 0; i < (size - 1); i++) {
value += edges[i];
}
return value;
}
One I've tried to find a cycle was by creating a new adjacency matrix for the edges and checking that before adding a new edge, but that did not perform as expected. I also tried to build a 3D matrix, but I could not get that to work either.
What's a new approach I should try to prevent cycles?
You should add the edge if the lowest common ancestor(LCA) of the two vertices corresponding to that edge is not root.
I'm trying to do a method where I have to delete a number from a vector of integers, and that number is passed as a parameter. The problem that I'm having right now is that when I try to delete the same number in consecutive positions, only one of them is deleted.
For example:
vector = (1, 2, 2, 3, 4, 5) and I want to remove the number "2", the result will be:
vector = (1, 2, 3, 4, 5)
But if the number is not in consecutive positions, the method works fine:
vector = (1, 2, 3, 2, 4, 5) ---> remove "2"
vector = (1, 3, 4, 5)
The code that I have is this:
void deleteNumber(int n, vector<int> &numbers)
{
bool hasEntered = false;
int counter = 0;
vector<int> deletedNumbers;
for(unsigned i = 0; i < numbers.size(); i++)
{
if(numbers[i] != n)
{
counter++;
}
else
{
counter = 0;
int counter2 = 0;
bool deleted = false;
for(unsigned j = 0; j < deletedNumbers.size() && deleted == false; j++) // Check if a number has been deleted before
{
if(deletedNumbers[j] != n)
{
counter2++;
}
else
{
deleted = true;
counter2 = 0;
}
}
if(counter2 == (int) deletedNumbers.size()) // Remove the number if it hasn't been removed
{
deletedNumbers.push_back(n);
for(unsigned k = 0; k<numbers.size(); k++)
{
if(numbers[k] == n)
numbers.erase(numbers.begin()+k);
}
counter2 = 0;
hasEntered = true;
}
}
}
}
I think that the error could be in the condition of the last for, where I finally remove the number.
The counters are used in order to determine if an element has been found or not. And also the method has to check if the item has been removed before.
If you don't understand something, please ask me.
Thanks in advance :)
you could try something like this:
void deleteNumber(int n, vector<int> &numbers)
{
vector<int>numbers_without_n;
for(unsigned i = 0; i < numbers.size(); i++)
if(numbers[i] != n)
numbers_without_n.push_back(numbers[i]);
numbers = numbers_without_n;
}
Your code looks like too complicated, thus it can contain many bugs.
This would delete all instances of n; O(numbers.size()):
void deleteNumber(int n, vector<int> &numbers) {
int i = 0;
for (int j = 0; j < numbers.size(); ++j) {
if (numbers[j] != n) numbers[i++] = numbers[j];
}
numbers.resize(i);
}
This would delete the first instance of n in each run; O(numbers.size()):
void deleteNumber(int n, vector<int> &numbers) {
int i = 0;
for (int j = 0; j < numbers.size();) {
if (numbers[j] == n) {
for (++j; j < numbers.size() && numbers[j] == n; ++j) {
numbers[i++] = numbers[j];
}
} else {
numbers[i++] = numbers[j++];
}
}
numbers.resize(i);
}
This would delete the first instance of n; O(numbers.size()):
void deleteNumber(int n, vector<int> &numbers) {
int i = 0;
for (int j = 0; j < numbers.size(); ++j) {
if (numbers[j] == n) {
for (++j; j < numbers.size(); ++j) {
numbers[i++] = numbers[j];
}
break;
}
numbers[i++] = numbers[j];
}
numbers.resize(i);
}
Pick whichever you need.
Please note that other answers, such as luk32's answer contain simpler code (using more STL) for deleting the first instance of n.
If you want to find and fix the bug in your code, I recommend that you try to find a very short input vector for which it fails, and then single-step through it in a debugger.
You don't need to have a loop inside the loop. The easiest way to handle the delete is to delete one item at a time and realize that this will mean you don't want to increment i when you have deleted an item. The easiest way to cancel the increment of i in the for loop is to decrement it first using --i. So you loop becomes
Check if the item matches the number
If so, delete the item and decrement i
Use std::remove and vector::erase
#include <algorithm>
void deleteNumber(int n, vector<int>& numbers)
{
numbers.erase(std::remove(numbers.begin(), numbers.end(), n), numbers.end());
}
First, I'm not sure what counter and counter2 are used for - if they're just being used to determine if you've iterated to the end of the vector without finding an element, you don't need them.
For the purpose of 'check if a number has been deleted', you just need a single boolean variable at the very top of the method, i.e. not inside the scope of the for loop.
I believe the following:
if(counter2 == (int) deletedNumbers.size()) // Remove the numbers if it hasn't been removed
can be replaced with if (!deleted).
So, here's a 'fixed' version while trying to stay as close to your existing logic as possible based on your code comments. This may not be the most efficient/elegant implementation however, I believe I have seen some other answers that use algorithms from the STL library to achieve the same thing.
void deleteNumber(int n, vector<int> &numbers)
{
bool deleted = false;
for(unsigned i = 0; i < numbers.size(); i++)
{
if (numbers[i] == n) // If we've found an instance of the number we're trying to delete
{
if (!deleted) // Check if an instance has already been deleted
{
numbers.erase(numbers.begin() + i); // Remove the number
deleted = true; // Flag that we have deleted an instance of the number
}
}
}
}
Alternately, instead of using a flag for 'deleted' to prevent deleting numbers after the first instance, you could optimize by just returning after you delete the first instance - that will prevent the rest of the loop from executing.
Ok, since apparently std::vector::erase does exists I would use standard c++ features:
void deleteNumber(int n, vector<int> &numbers) {
auto it = find(std::begin(numbers), std::end(numbers), n);
if(it != numbers.end()) numbers.erase(it);
}
EDIT: Forgot that end() is not a valid argument for erase.
Im coming accross a very annoying problem here. my goal in this challenge is to return an array, holding the names of the 5 most active buyers by volume. stockSymbols is holding those names, while the total bought is successfully worked out and placed into the totalBought array. I then tried to work out the top 5 largest and put their names into totalSold and return.
I am an absolute novice at c++, so I am aware this way of doing things is incorrect. It also wont compile, its throwing memory errors all over the place (starting at or around the if(biggest[0] < totalBought[i])) line.
If any of you know a better way of making this work successfully I would be grateful for your input, or if you know how to make this way work that would also be very useful. I would really love to find the most efficient way (in terms of speed) to compute this though.
Many thanks.
string* Analyser::topFiveBuyers()
{
// Your code
string* totalSold;
totalSold = new string[5];
string stockSymbols[] = {"W Buffet", "P Lynch", "G Soros", "J Neff", "Hargreaves Lansdown",
"Sippdeal", "Saga", "Halifax", "iWeb", "Alliance Trust", "Clubfinance", "Lloyds TSB", "Saxo" };
int totalBought[13];
for(int i = 0; i < nTransactions; i++)
{
for(int j = 0; j < 13; j++)
{
if(transArray[i].buyerName == stockSymbols[j])
{
totalBought[j] += transArray[i].numShares;
}
}
}
int biggest[] = {-1, -1, -1, -1, -1};
for(int i = 0; i < 13; i++)
{
if(biggest[0] < totalBought[i])
{
biggest[4] = biggest[3];
biggest[3] = biggest[2];
biggest[2] = biggest[1];
biggest[1] = biggest[0];
biggest[0] = totalBought[i];
totalSold[0] = stockSymbols[i];
}
else if(biggest[1] < totalBought[i])
{
biggest[4] = biggest[3];
biggest[3] = biggest[2];
biggest[2] = biggest[1];
biggest[1] = totalBought[i];
totalSold[1] = stockSymbols[i];
}
else if(biggest[2] < totalBought[i])
{
biggest[4] = biggest[3];
biggest[3] = biggest[2];
biggest[2] = totalBought[i];
totalSold[2] = stockSymbols[i];
}
else if(biggest[3] < totalBought[i])
{
biggest[4] = biggest[3];
biggest[3] = totalBought[i];
totalSold[3] = stockSymbols[i];
}
else if(biggest[4] < totalBought[i])
{
biggest[4] = totalBought[i];
totalSold[4] = stockSymbols[i];
}
}
return totalSold;
}
I suggest a combination map and multi map for achieving what you want. I took the liberty of changing the result of the function to be a vector of strings, which it honestly should be:
std::vector<string> Analyzer::topFiveBuyers()
{
typedef map<string, int> xact_map;
xact_map xacts;
for (int i=0;i<nTransactions;++i)
xacts[transArray[i].buyerName] += transArray[i].numShares;
// enumerate the map, beginning to end, throwing all elements
// into a multimap keyed by transaction count rather than name.
// note this considers an element "less" (and therefore at the
// beginning of the sort order) if the share count is *greater*.
typedef multimap<int, string, std::greater<int>> highest_map;
highest_map highest;
for (xact_map::const_iterator it=xacts.begin(); it != xacts.end(); ++it)
highest.insert(highest_map::value_type(it->second, it->first));
// now just peel off the top five elements from the multimap.
vector<string> results;
int n=0;
for (highest_map::const_iterator it=highest.begin();
it != highest.end() && n<5; ++it,++n)
{
results.push_back(it->second);
}
return results;
}