Why this Dijkstra (graph) implementation isn't working? - c++

I made this implementation for this problem :
http://www.spoj.pl/problems/SHOP/
#include<iostream>
#include<stdio.h>
#include<queue>
#include<conio.h>
#include<string.h>
using namespace std;
struct node
{
int x;
int y;
int time;
};
bool operator <(const node &s,const node &r)
{
if(s.time>r.time)
return true;
else return false;
}
node beg,src,dest,tempa;
int b,a,temp;
int map[25][25];
bool vis[25][25];
int X[]={1,0,-1,0};
int Y[]={0,1,0,-1};
int djs_bfs(node src,node dest)
{
int result=0;
priority_queue<node>pq;
pq.push(src);
while(!pq.empty())
{
node top = pq.top();
pq.pop();
if(top.x==dest.x && top.y==dest.y) return result;
if(top.x<0 || top.x>=a) continue;
if(top.y<0 || top.y>=b) continue;
if(vis[top.x][top.y]) continue;
vis[top.x][top.y]=true;
result+=map[top.x][top.y];
for(int i=0;i<4;i++)
{
tempa.x=top.x+X[0];
tempa.y=top.y+Y[0];
tempa.time=map[top.x+X[0]][top.y+Y[0]];
pq.push(tempa);
}
}
return -1;
}
int main()
{
memset(vis,false,sizeof(vis));
scanf("%d %d",&a,&b);
while(a != 0)
{
for(int i=0;i<a;i++)
for(int j=0;j<b;j++)
{
scanf("%c",&temp);
if(temp=='X') {map[i][j]=0;vis[i][j]=true;}
if(temp=='S') {src.x=i;src.y=j;src.time=0;}
if(temp=='D') {dest.x=i;dest.y=j;dest.time=0;}
else map[i][j]=temp-'0';
}
cout<<djs_bfs(src,dest)<<endl;
scanf("%d %d",&a,&b);
}
return 0;
getch();
}
I don't know why my code doesn't generate the right answer for the testcases.
If someone can help me improve the code, please do so :D

First of all, the graph parsing code is incorrect. The first line specifies width and height, where the width is the number of characters per line the height is the number of lines. Therefore, swap &a and &b in the first scanf, or swap the order of the nested for loops (but not both). Also, I had to add dummy scanf("%c", &dummy); calls at various places to filter out newlines. A simple dump, such as this, will help determine if your map was parsed correctly:
cout << "a=" << a << endl;
cout << "b=" << b << endl;
for (int i=0; i<a; i++) {
for(int j=0; j<b; j++) {
cout << (char)('0' + map[i][j]) << ",";
}
cout << endl;
}
Note: I also set map[i][j] to 0 for 'S' and 'D', also changing the repeated if statements into an if; else if; else chain. This makes the algorithm more robust, since you can generically add time from the source or destination.
Now, on to the algorithm itself....
Each loop of the algorithm increments result by the current map location weight. However, the algorithm is searching multiple paths simultaneously (i.e., the number of entries in the priority queue), and therefore result ends up being the sum of all processed node weights, not the current path weight. The current path weight is top.temp, and therefore you can eliminate the result variable and simply return top.temp when you reach the destination.
Also, as other answers noted, you need to use X[i] and Y[i] in your inner loop, otherwise you are only searching in one direction.
Now, because of the addition/subtraction from X[i] and Y[i], you will likely access map[][] out of range (-1 or 25). Therefore, I recommend moving the if guards to the inner for loop to guard against the out-of-range access. This also avoids filling the priority queue with illegal possibilities.
Here is my version of the algorithm, with minimal corrections, for reference:
priority_queue<node>pq;
pq.push(src);
while(!pq.empty())
{
node top = pq.top();
pq.pop();
if(top.x==dest.x && top.y==dest.y) return top.time;
if(vis[top.x][top.y]) continue;
vis[top.x][top.y]=true;
for(int i=0;i<4;i++)
{
tempa.x=top.x+X[i];
tempa.y=top.y+Y[i];
if(tempa.x<0 || tempa.x>=a) continue;
if(tempa.y<0 || tempa.y>=b) continue;
tempa.time=top.time + map[tempa.x][tempa.y];
pq.push(tempa);
}
}
return -1;
I hope this helps.

Why do you have 0 indexes?
tempa.x=top.x+X[0];
tempa.y=top.y+Y[0];
tempa.time=map[top.x+X[0]][top.y+Y[0]];
Nitpick:
bool operator <(const node &s,const node &r)
{
if(s.time>r.time)
return true;
else return false;
}
Isn't this more readable:
bool operator <(const node &s,const node &r)
{
return (s.time>r.time);
}

You're using X[0] and Y[0] instead of X[i] and Y[i] in that inner loop.
By the way, other than that your Dijkstra's is very inefficient. First, you're pushing nodes onto the queue even when they have already been visited, and secondly, you may have several of the same node in the queue, just with different times. Ultimately neither of these things effect the outcome, but you're changing the complexity.
Edit: Oh, tempa.time should equal top.time plus the edge weight, not just the edge weight.

Related

Shortest path in an unweighted graph, using user input in C++

As I was practicing C++ today, I came across a code which finds the shortest path in an unweighted graph using BFS and outputs the length of the path and the vertices it travelled through.
I attempted to change up this code by introducing user input.
First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges.
The next M lines contain two integers, which indicates an undirected edge between two nodes.
I attempted to change the code in accordance to this, but I ran into a number of problems.
The first problem is that if I use gcc, the program will end after the for loop runs once in the main function.
However, if I use clang, the program runs fine. But there is an other issue and it relates to a very specific input.
The following input:
3 3
1 3
1 2
2 3
should return 1, but sometimes (specifically when I enter the input line by line) it returns the message: "Given source and destination are not connected". It is completely random.
The code is below:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[]);
void printShortestDistance(vector<int> adjList[], int s, int dest, int numOfVertices);
int main()
{
int numOfVertices, numOfEdges;
cin >> numOfVertices >> numOfEdges;
vector<int> adjList[numOfVertices];
if (2 <= numOfVertices && numOfVertices <= 1e5 && 1 <= numOfEdges && numOfEdges <= 1e5)
{
for (int i = 0; i < numOfEdges; i++)
{
int node1, node2;
cin >> node1 >> node2;
if ((1 <= node1) && (1 <= node2) && (node1 <= numOfVertices) && (node2 <= numOfVertices) && (node1 != node2))
{
adjList[node1].push_back(node2);
adjList[node2].push_back(node1);
}
else{ return EXIT_FAILURE; }
}
int source = 1;
int dest = numOfVertices;
printShortestDistance(adjList, source, dest, numOfVertices);
}
}
void printShortestDistance(vector<int> adjList[], int source, int dest, int numOfVertices)
{
int pred[numOfVertices];
int dist[numOfVertices];
if (BFS(adjList, source, dest, numOfVertices, pred, dist) == false)
{
cout << "Given source and destination are not connected";
return;
}
vector<int> path;
int crawl = dest;
path.push_back(crawl);
while (pred[crawl] != -1)
{
path.push_back(pred[crawl]);
crawl = pred[crawl];
}
cout << "Shortest path length is : " << dist[dest];
cout << "\nPath is::\n";
for (int i = path.size() - 1; i >= 0; i--)
cout << path[i] << " ";
}
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[])
{
list<int> queue;
bool visited[numOfVertices];
for (int i = 0; i < numOfVertices; i++)
{
visited[i] = false;
dist[i] = INT_MAX;
pred[i] = -1;
}
visited[source] = true;
dist[source] = 0;
queue.push_back(source);
while (!queue.empty())
{
int u = queue.front();
queue.pop_front();
for (int i = 0; i < adjList[u].size(); i++)
{
if (visited[adjList[u][i]] == false)
{
visited[adjList[u][i]] = true;
dist[adjList[u][i]] = dist[u] + 1;
pred[adjList[u][i]] = u;
queue.push_back(adjList[u][i]);
// We stop BFS when we find
// destination.
if (adjList[u][i] == dest)
return true;
}
}
}
return false;
}
"First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges."
This is not a good idea. Humans are terrible at counting, while computers are pretty good at it. So do not make your users count the vertices and edges - they will often get it wrong and cause chaos.
Just input the start and ending nodes of an edge. If a node is already present in the data structure, connect it. If node not already present then add it and then connect it.
You will have much happier users!
I see that you have decided to store your graph in an adjacency list. This is a perfectly reasonable idea, but the snag is that it is quite a challenge to code. This seems to be your first attempt to code a graph theory problem, so I recommend that you use an adjacency matrix instead since it is much easier to code.
For small graphs the difference is insignificant, so you need only consider switching to the more complicate adjacency list when you are working with enormous graphs ( many thousands of nodes )
Remember that vectors in C++ are 0-based.
In your example, numOfVertices and numOfEdges are both 3, so node 3 will lead to out-of-bound access. Either change your input to 0-based node numbers or use node1-1 and node2-1.
See also
Vector going out of bounds without giving error
and the accepted answer.

program for n-queens problem only works for n<=10 even though it should work for all n

The n-queens problem asks how many different ways are there to put n queens on a n-by-n board such that the queens cannot attack each other in one move. I've written a program which partially solves this problem. I say partially because my program only works for n<=10. However, I did not specify or hard-code the value 10, or any other value, in my code.
For example, my code outputs 92 solutions for 8-by-8, 352 for 9-by-9, and 724 for 10-by-10. These are the expected values as stated on the n-queens wikipedia page. However, my code outputs 1649 for 11-by-11. The expected answer is 2,680.
I really have no idea why this would occur.
using namespace std;
class Board{
struct Position{
int r;
int c;
};
public:
int size;
vector<vector<int> > b;
Position pos;
vector<int> placements;
int count;
Board(int s){
size=s;
pos.r=0;
pos.c=0;
for(int i=0; i<s; i++){
b.push_back(vector<int>());
for(int j=0; j<s; j++){
b.at(i).push_back(0);
}
}
count=0;
}
bool hasQueens(){
for(int i=0; size-i>=0; i++){
if(b[pos.r][pos.c-i]==1){
return true;
}
if(pos.r-i >= 0){
if(b[pos.r-i][pos.c-i]==1){
return true;
}
}
if(pos.r+i < size){
if(b[pos.r+i][pos.c-i]==1){
return true;
}
}
}
return false;
}
void placeQueen(){
b[pos.r][pos.c]=1;
placements.push_back(pos.r);
}
void backtrack(){
pos.c--;
b[placements[pos.c]][pos.c]=0;
pos.r = placements[pos.c] +1;
placements.pop_back();
if(pos.r==size) backtrack();
}
bool canBacktrack(){
if(pos.c==1 && placements[0]==size-1) return false;
else return true;
}
void nextSol(){
while(pos.c!=size){ //while the board is not filled
if(pos.r==size && canBacktrack()){
backtrack();
} else if(pos.r==size && !canBacktrack()){
break;
}else if(!hasQueens()){
placeQueen();
pos.r=0;
pos.c++;
} else {
pos.r++;
}
}
}
void print(){
for(int i=0; i<size; i++){
for(int j=0; j<size; j++){
cout << b[i][j];
}
cout<<endl;
}
cout<<endl;
}
};
int main(){
Board board(11);
board.print();
while(true){
board.nextSol();
if(!board.canBacktrack()) break;
cout << ++board.count << endl;
board.backtrack();
}
}
Your code segfaults for me. Running it through valgrind says that there is invalid read in this line:
if(b[pos.r][pos.c-i]==1){
in function hasQueens(). And indeed, there are cases in which pos.c-i becomes negative: whenever pos.c is smaller than size.
The organization of the code is messy, I would suggest to write your boundaries out clearly instead of relying on stopping for col == 1 and r == size (which if access incorrectly can cause a segfault). Also, NQueen problem has an elegant solution with recursion, I would suggest to look into that as well.
I was able to make some changes to your program and got the expected answer for 11 x 11, however I think there are more bugs in the code. The problem lies in the backtrack() and placeQueen() function, pos.c is decremented without checking if it's greater than 0, so it can potentially go negative and crash when access. Most importantly you don't need to do push_back/pop_back on the placement vector since you know you only can place one queen on each column so it should really be fixed size. when placing queen, you can do placement[c] = r. Hope this helps.

Count Inversions with merge sort in C++

I'm working on my first few algorithms to build my C++ skills and am currently coding up a method of counting inversions with merge sort. I've managed to get a working merge sort together but I'm having a bit of trouble keeping track of the number of inversions. Any ideas of where to go from here? How can I keep track of the number of inversions on a recursive algorithm like this? Additionally I've seen a couple different implementations of this in my internet travels and have found most people stray away from the std::vector method, any idea why? Thanks for any help, my code is below!
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
vector<int> print(vector<int> input){
for(int i=0; i<input.size(); i++){
cout<<input[i]<<",";
}
cout<<endl;
return input;
}
vector<int> merge(vector<int> left,vector<int> right){
//set up some varibles
vector<int> output;
int i=0;
int j=0;
//loop through the lists and merge
while(i<left.size() && j<right.size()){
//push the smallest of the two to the vector output
if(left[i]<=right[j]){
output.push_back(left[i]);
i+=1;
}
if(left[i]>right[i]){
output.push_back(right[j]);
j+=1;
}
}
//push the remnants of the vectors to output
for(i; i<left.size(); i++){
output.push_back(left[i]);
}
for(j; j<right.size(); j++){
output.push_back(right[j]);
}
return output;
}//end merge
vector<int> merge_sort(vector<int> input){
//check the size of the vector
if(input.size()<2){
return input;
}
else{
//int new vectors
vector<int> left;
vector<int> right;
vector<int> output;
//find the middle of the input vector
int middle=(input.size())/2;
//build the left vector
for(int i=0; i<middle; i++){
left.push_back(input[i]);
}
//build the right vector
for(int i=middle; i<input.size(); i++){
right.push_back(input[i]);
}
//make recursive calls
left=merge_sort(left);
right=merge_sort(right);
//call merge
output=merge(left,right);
return output;
}
}
int main()
{
vector<int> output;
vector<int> input;
input.push_back(2);
input.push_back(1);
input.push_back(10);
input.push_back(4);
output=merge_sort(input);
print(output);
}
Good news: counting inversions is pretty easy from here.
Think about your "merge" method. Every time you put an element from the left vector into output, you are not changing its position relative to elements from the right. On the other hand, every time you add an element from the right vector, you are putting it "before" all elements still to be processed in the left vector, when it was prevously "after" them, i.e. creating (left.size - i) "inversions".
You can prove this easily by induction if needed.
So the answer is simply : pass an int* to your merge method, and increment it by (left.size - i) every time you push an element from the right vector.
EDIT: Working code sample
#include <iostream>
#include <vector>
// removed useless dependency math.h
using namespace std;
// void type -> does not return anything
void print (vector<int> input) {
// range-based for loop (since C++ 11)
// no brackets -> only one instruction in for loop
for(int i : input)
cout << i << ",";
}
vector<int> merge (vector<int> left, vector<int> right, int * inv_count) {
vector<int> output;
// multiple variable definition of the same type
int i=0, j=0;
// spaces around "<", after "while", before "{" for readability
while (i < left.size() && j < right.size()) {
// one-instruction trick again
if (left[i] <= right[j])
// i++ is evaluated to <previous value of i> and then increments i
// this is strictly equivalent to your code, but shorter
// check the difference with ++i
output.push_back(left[i++]);
// else because the two conditions were complementary
else {
output.push_back(right[j++]);
// pointer incrementation
*inv_count += (left.size() - i);
}
}
// first field of for ommited because there is no need to initialize i
for(; i < left.size(); i++)
output.push_back(left[i]);
for(; j < right.size(); j++)
output.push_back(right[j]);
return output;
}
vector<int> merge_sort (vector<int> input, int * inv_count) {
// no-braces-idiom again
// spaces around "<" and after "if" for readability
if (input.size() < 2)
return input;
// no need for else keyword because of the return
// multiple variable definition
vector<int> left, right;
int middle = input.size() / 2;
// one-instruction for loop
for(int i=0; i < middle; i++)
left.push_back(input[i]);
for(int i=middle; i < input.size(); i++)
right.push_back(input[i]);
// no need for intermediate variable
return merge( merge_sort(left, inv_count),
merge_sort(right, inv_count),
inv_count);
}
// consistent convention : brace on the same line as function name with a space
int main () {
// vector initialization (valid only since C++ 11)
vector<int> input = {2, 1, 10, 4, 42, 3, 21, 7};
int inv_count = 0;
// No need for intermediate variables again, you can chain functions
print( merge_sort(input, &inv_count) );
// The value inv_count was modified although not returned
cout << "-> " << inv_count << " inversions" << endl;
}
I modified your code to include a few usual C++ idioms. Because you used the C++14 tag, I also used tricks available only since C++11. I do not recommend using all of these tricks everywhere, they are included here because it is a good learning experience.
I suggest you read about pointers before diving deeper into C++.
Also note that this code is in no way optimal : too many intermediate vectors are created, and vectors are not useful here, arrays would be enough. But I'll leave this for another time.

Using struct with an insertion sort

I'm having some trouble with an insertion sort, passing in data from a struct.
It's returning the error: |98| cannot convert 'store' to 'int' in assignment.
struct store{
char tag[5];
int cost;
long int volume;
};
void costSort(store storedEntries[], int count);
void volumeSort(store storedEntries[], int count);
int main(){
store record[100];
ifstream fin;
char choice;
int count = 0;
fin.open("stockdata.txt");
//file read in
if(fin.good())
{
while(!fin.eof())
{
fin >> record[count].tag;
fin >> record[count].cost;
fin >> record[count].volume;
count++;
}
count--;
}
cout << "Main Menu:" << endl;
cout << "c: sort data by Cost\nv: sort data by trade Volume\nq: Quit\nEnter Choice: ";
cin >> choice;
switch(choice)
{
case 'C':
case 'c': //costSort(record, count);
break;
case 'V':
case 'v': volumeSort(record, count);
break;
case 'q':
case 'Q': return 0;
break;
}
return 0;
}
void volumeSort(store record[], int count)
{
int p = 0, item = 0;
for(int i=1; i<count; i++){
cout << "test";
item = record[i];
p = (i - 1);
while(p>=0 && item < record[p]){
record[p+1] = record[p];
p--;
}
record[p+1] = item;
cout << record[i].tag << " " << record[i].volume << endl;
}
}
The insertion sort is in the function void volumeSort().
Any advice would be appreciated, i haven't had any issues up until now :S
You're comparing non-like types with no operator provided to support the comparison (and none needed if this is done correctly). Currently you're comparing int to store. What you should be comparing is two volume members of two store objects.
A simple loop that is probably closer to what you want would be something like this:
// note: count is size_t, an unsigned magnitude. only used signed
// integer types where it makes sense a negative integer will be
// plausible input.
void volumeSort(store record[], size_t count)
{
for(size_t i=1; i<count; ++i)
{
// compare current element to one below us, swapping if needed
// and stopping as soon as we reach an equal or lesser record
size_t j=i;
while(j>0 && record[j].volume < record[j-1].volume)
{
std::swap(record[j-1], record[j]);
--j;
}
}
}
Or something similar. Note the comparison of:
record[j].volume < record[j-1].volume
in the while condition. Apples to apples...
For an interesting insertion_sort that utilizes two wonderful features of the standard library, std::upper_bound and std::rotate, a rather dense version of the function can be created, looking something like this:
void insertion_sort(store record[], size_t len)
{
for (auto it = record; it != record+len; ++it)
{
std::rotate(std::upper_bound(record, it, *it,
[](const store& lhs, const store& rhs) { return lhs.volume < rhs.volume; }),
it, std::next(it));
}
}
This is considerably more efficient than it first may seem, as the search for the proper placement of the prospect element is done in O(logN) using std::upper_bound. Then std::rotate opens the hole where the element goes and it is swapped into place.
Just some food for thought. Coupled with the comparator that is going to inlined by even remedial optimization and it has a lot more punch than you may first think. Still not as kick-ass as std::sort, usually highly optimized utilizing multiple algorithms, but still good brain food.
Best of luck.
You are trying to compare a int with a store.
This will not work unless you overload < operator to compare a int and a store.
store record[];
int p = 0, item = 0;
//[...]
while (p >= 0 && item < record[p])
//Neither can you assign that
record[p + 1] = item;
Operator example:
bool operator<(const int &left, const store &s)
{
//You could also do some calculation in here,
//if you want to compare a value inside the struct
//like this:
return left < s.cost;
//Please... do it in place.
//item < record[p].cost;
}
if you want to sort by volume you should take
record[i].volume even when comparing...the types should be same when comparing values..
Similarly for other cases..

Why is my program not printing perfect integers?

I am new to C++ programming and have a problem with one of my programs
#include <iostream>
using namespace std;
bool IsPerfect(int n);
int main ()
{
for(int i=1; i<100; i++){
IsPerfect(i);
}
return 0;
}
bool IsPerfect(int n){
int sum;
for(int x=1; x<n; x++){
if(n%x==0){
sum+=x;
return true;
cout <<n;
}
else{
return false;
}
}
}
I am trying to create a program that will list perfect numbers but I can't find the bug as to why it would not print.
I see 3 issues:
Your algorithm is wrong. Your loop terminates on the first time a number is evenly divisible by any factor (including 1). See Wikipedia for an explanation of the algorithm.
You have an uninitialized variable with int sum; Also, you only ever write to it, you don't read it in a useful manner ever.
You have unreachable code. Your cout << n; in the loop will never be hit.
Try the following corrected code:
#include <iostream>
#include <cassert>
using namespace std;
bool IsPerfect(int n)
{
int sum = 1;
for(int x = 2; x < n; ++x)
{
if(n % x == 0)
sum += x;
}
return sum == n;
}
int main ()
{
for(int i=1; i<100; i++){
if (IsPerfect(i))
cout << i << endl;
}
assert(IsPerfect(6));
assert(IsPerfect(28));
assert(IsPerfect(496));
return 0;
}
You have a return statement before you output statement here:
return true;
cout <<n;
you need to swap the order of these statements, you also probably want to add a comma or some other separator:
std::cout << n << ", " ;
return true;
I am not sure that is where you want to return from since you will exit the first time you enter that if statement, which will happen when x is 1.
If you want to capture perfect numbers - numbers which are equal to the sum of their divisors, correct? - you need to allow the loop to proceed (and the sum to actually, well, sum) without returning. Take your print statement and your return statements and place them after the end of your loop; you should be checking then if the sum you have calculated is equal to n.
All these answers are telling you to write the number before returning. But that's ignoring the poor design here: you have a function that decides whether a number is perfect; it should not be that function that also decides what to do with this information (print it, store it, send it over the network, ...).
This will also make your code more readable, because the name IsPerfect is misleading - it tells the reader that this function just returns whether the number is perfect. Thus, the loop in the main function reads as, "for the integers 1 to 100, ask whether it is perfect and ignore the answer". This is not a useful program.
Remove the cout line from IsPerfect completely and put it in main instead:
for (int x = 1; x < 100; ++x) {
if (IsPerfect(x)) {
std::cout << x << '\n';
}
}
Try this
if(n%x==0){
sum+=x;
cout <<n;
return true;
}
The issue is in here:
if(n%x==0){
sum+=x;
return true;
cout <<n;
}
the keyword return immediately ends the function and returns the appropriate value (true). This means that all statements following it won't be executed. Try the following:
if(n%x==0){
sum+=x;
cout <<n;
return true;
}
In addition to the problems others have pointed out, you will never compute the right answer because you didn't initialize your sum variable.
Change
int sum;
to
int sum=0;