What is wrong with my dijkstras algorithm - c++

So I've been working on this for hours and I'm extremely frustrated. I don't understand what I'm doing wrong.
I'm using Dijkstra's Algorithm to find the shortest paths between a source vertex, and 4 other vertices using an adjacency matrix. The idea behind this is that there are 5 cities and flights going to and from them, and I need to find the cheapest ticket price, taking into account layovers.
I'm following the algorithm out of my book, which is in pseudocode, and the code on the following website: http://vinodcse.wordpress.com/2006/05/19/code-for-dijkstras-algorithm-in-c-2/
The problem I'm having is that in the nested for loop on the website, the counter i starts at 1, and I believe this is the reason why the distances from the source vertex to all the vertices are correct, except the first one which is unchanged at 999.
Example:
Current Distance: 999 220 0 115 130
Predecessors: 0 3 0 2 2
All of those distances are correct--even if I change the source vertex--except for the first one which remains unchanged.
If I change the counter i to 0, it messes up every distance, i.e.
Current Distance: 0 105 0 0 0
Anyway, Please help. Here is the relevant code.
void Graph::findDistance(int startingVertex)
{
for(int i=0; i<MAX;i++)
{
currentDistance[i] = 999;
toBeChecked[i] = 1;
predecessor[i] = 0;
}
currentDistance[startingVertex]=0;
bool flag=true;
int v;
while(flag)
{
v=minimum();
toBeChecked[v]=0;
for(int i=1; i<MAX;i++) //here is where i think im going wrong
{
if(adjecencyMatrix[v][i]>0)
{
if(toBeChecked[i]!=0)
{
if(currentDistance[i] > currentDistance[v]+adjecencyMatrix[v][i][0].ticketPrice)
{
currentDistance[i] = currentDistance[v]+adjecencyMatrix[v][i][0].ticketPrice;
predecessor[i]=v;
}
}
}
}
flag = false;
for(int i=1; i<MAX;i++)
{
if(toBeChecked[i]==1)
flag=true;
}
}
}
int Graph::minimum()
{
int min=999;
int i,t;
for(i=0;i<MAX;i++)
{
if(toBeChecked[i]!=0)
{
if(min>=currentDistance[i])
{
min=currentDistance[i];
t=i;
}
}
}
return t;
}

Shouldn't this check
if(adjecencyMatrix[v][i]>0)
be done with adjecencyMatrix[v][i][0].ticketPrice, like the rest of the comparisons?
If adjecencyMatrix[v][i] is an array, it is getting converted to a pointer, and that pointer will always compare greater than 0. Array-to-pointer decay strikes again :)

Related

leetcode question 81 c++ returns wrong answer

question:
There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).
Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].
Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.
You must decrease the overall operation steps as much as possible.
class Solution {
public:
int search(vector<int>& nums, int target) {
int s=0;
vector<int> f(4999);
vector<int> x(4999);
int y=f.size()-1;
int z=x.size()-1;
for (int i=0;i<nums.size();i++){
for (int j=1;j<nums.size();j++){
if (i<=j){
f.push_back(nums[i]);
}else if (i>j){
f.push_back(nums[i]);
x.push_back(nums[j]);
for (int k=j;k<nums.size();k++)
x.push_back(nums[k]);
break;
}
}
}
if (target==x[0]||target==f[0]){
return true;
}
else if (target>f[0]){
while (s<=y){
int mid=0;
mid=(y+s)/2;
if (f[mid]>target){
y=mid-1;
}else if (f[mid]<target){
s=mid+1;
}else if (f[mid]==target){
return true;
}
}
return false;
}else if (target<f[0]){
while (s<=z){
int mid=0;
mid=(z+s)/2;
if (x[mid]>target){
z=mid-1;
}else if (x[mid]<target){
s=mid+1;
}else if (x[mid]==target){
return true;
}
}
return false;
}
else{
return false;
}return false;
}
};
input [2,5,6,0,0,1,2] target 2 returned false expected true
input [1] target 1 returned false expected true
input [1] target 0 returned true expected false
trying to stick to a binary search solution how can this work
help is appriciated thanks
To figure out why it's not working, you can walk through one of the failing test cases. You'd want to pick the easiest one to manage in your head, so in this case I recommend one of those with an array length of 1.
So let's walk through
input [1] target 1 returned false expected true
Your function first creates two large arrays, each with 4999 zeros in them. See this answer for why they're zero.
Then that nested for loop runs, but it doesn't actually do anything because the inner loop will not run -- j=1 is not less than nums.size(), which is 1.
So by the time you do your binary searches below, both f and x are filled with 4999 zeros. Your code does the binary search on f, so it won't find your target of 1.
If you want to see the solution to this problem, check out this Stack Overflow answer.

I am trying to make prims algorithm using c++ STL. After the iterator iterates 1st time it stops the code and gives wrong output

First I have created an un-directed graph of vertices, edges and weights.
In prims() function:
vertex[] array is initialized to INT_MAX for all indices i < n except 0 index. It will have smallest weights found till now.
bool isthere[] array to check either a vertex is visited or not.
list<int> s at first will have 5 (0-4 indices) values. After each for loop its value will pop.
vector<int> mset will keep the vertex chosen according to their smallest weight.
#include<bits/stdc++.h>
using namespace std;
void addEdge(vector<pair<int,int>>adj[],int u,int v,int wt){
adj[u].push_back(make_pair(v,wt));
adj[v].push_back(make_pair(u,wt));
}
void print(vector<pair<int,int>>adj[],int v){
for(int i=0;i<v;++i){
cout<<i<<"-->";
vector<pair<int,int>>::iterator it;
for(it=adj[i].begin();it!=adj[i].end();++it){
cout<<it->first<<"-"<<it->second<<" ";
}
cout<<"\n";
}
}
void prims(vector<pair<int,int>>adj[],int v){
int vertex[v];
bool isthere[v];
vertex[0]=0;
isthere[0]=true;
list<int>s;
s.push_back(0);
for(int i=1;i<v;++i){
vertex[i]=INT_MAX;
isthere[i]=false;
s.push_back(i);
}
vector<int>mset;
int i=0;
while(!s.empty()){
isthere[i]=true;
mset.push_back(i);
s.pop_back();
cout<<"i="<<i<<" ";
int lesser=INT_MAX;
vector<pair<int,int>>::iterator it;
for(it=adj[i].begin();it!=adj[i].end();++it){
cout<<"it-"<<it->first<<" "<<it->second<<"\n";
if(isthere[it->first]==false && vertex[it->first]>it->second){
if(lesser>it->second){
lesser=it->second;
i=it->first;
cout<<"i="<<i<<" ";
}
vertex[it->first]=it->second;
}
}
}
}
int main(){
int v=5;
vector<pair<int,int>>adj[v];
addEdge(adj,0,1,2);
addEdge(adj,0,2,8);
addEdge(adj,1,3,21);
addEdge(adj,4,1,6);
addEdge(adj,2,1,0);
addEdge(adj,2,4,5);
addEdge(adj,3,4,9);
print(adj,v);
prims(adj,v);
return 0;
}
Here's my adjacency list. It is an array of vector of pairs denoting vertex, weight.
0-->1-2 2-8
1-->0-2 3-21 4-6 2-0
2-->0-8 1-0 4-5
3-->1-21 4-9
4-->1-6 2-5 3-9
Here's the debug output and the error I got in the prims() function.
i=0 it-1 2
i=1 it-2 8
it-0 0
it- -874898181 134251312
Process returned -1073741819 (0xC0000005) execution time : 0.835 s
Press any key to continue.
for(it=adj[i].begin();it!=adj[i].end();++it){
// ...
i=it->first;
// ...
}
This code exhibits undefined behavior, as it compares an iterator into one container with iterator into a different one. it is initialized with, say, adj[0].begin(), then i changes inside the loop, and on the next iteration the iterator is compared with, say, adj[1].end()

Minor bug in C++ dfs question in a big test case

I am solving a question on leetcode, my answer passed 123 test cases and failed on one. I can't figure out my problem because the test case is large and my solution works with every small testcase I could think of. The discussion section of leetcode wasn't helpful so I thought id try here.
question is: "You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water.
Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells).
The island doesn't have "lakes" (water inside that isn't connected to the water around the island). One cell is a square with side length 1. The grid is rectangular, width and height don't exceed 100. Determine the perimeter of the island."
example test case: [[0,1,0,0],
[1,1,1,0],
[0,1,0,0],
[1,1,0,0]]
Output: 16
https://leetcode.com/problems/island-perimeter/
my solution
class Solution {
public:
bool dfs(unordered_set<string> & set, vector<vector<int>> &grid, int x,int y, int& count)
{
if(x>=grid.size()||y>=grid[0].size()||y<0||x<0)
{
return false; // false means current coordinate is not an island piece
}
string loco=to_string(x)+to_string(y);
if(grid[x][y]==0)
return false;
if(set.find(loco)!=set.end())
{
return true;
}
set.insert(loco); //insert island piece to visited pieces
int temp=4-(dfs(set,grid,x+1,y,count)+dfs(set,grid,x-1,y,count)+dfs(set,grid,x,y+1,count)+dfs(set,grid,x,y-1,count)); //subtract the number of adjecent island pieces
count+=temp;
return true;
}
int islandPerimeter(vector<vector<int>>& grid) {
unordered_set<string>set;
int count=0;
for(int i=0 ;i <grid.size();i++)
{
for(int j=0;j<grid[0].size();j++)
{
if(grid[i][j]==1) //find the first piece of island and run DFS
{
dfs(set,grid,i,j,count);
return count;
}
}
}
return count;
}
};
I have checked the discussion section of leetcode but most of the solutions were iterative and didn't use DFS like i did. I am trying to understand what the problem is with my solution.
The testcase that failed is :
[[0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,0],
[0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,0,0,1,0],
[0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0],
[0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],
[0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,0,0,0],
[0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0],[0,0,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0]]
expected output=128
my output= 125
You are using string loco=to_string(x)+to_string(y); as the key for your std::set. Clearly, if x = 11 and y = 1 then the key is 111, just as when x = 1 and y = 11, which can break your algorithm.
Using a std::string as the set key is an unusual choice in the first place. I would recommend using std::pair<int, int> instead. Using your own type dedicated for this purpose (struct Coordinate { int x, y; };) would be even clearer but would need some additional boilerplate (namely operator<) to work with std::set, whereas std::pair has this out-of-the-box.

Sort Optimisation time

I have 2 sorts:
void sort1(std::vector<int> &toSort)
{
for(VintIter i=toSort.begin(); i!=toSort.end(); i++)
{
for (VintIter j =(toSort.end()-1); j != i; --j)
{
if (*(j - 1) > *(j))
{
std::iter_swap(j - 1, j);
}
}
}
}
void sort2(std::vector<int> &toSort)
{
for(int i= 0; i<(toSort.size()-1); i++)
{
int minElem=i,maxElem=i+1;
if(toSort[minElem]>toSort[maxElem])
{
std::swap(toSort[minElem],toSort[maxElem]);
}
while(minElem>0 && toSort[minElem]<toSort[minElem-1])
{
std::swap(toSort[minElem],toSort[minElem-1]);
minElem--;
}
while(maxElem<(toSort.size()-1) && toSort[maxElem]>toSort[maxElem+1])
{
std::swap(toSort[maxElem],toSort[maxElem+1]);
maxElem++;
}
}
}
And I'm using QueryPerformanceFrequency and QueryPerformanceCounter to get times of those.
For Random vector of 1000 elements for sort1 returns 20.3 and for sort2 5.4. And this is ok..
But when I'm trying to get resoults for sorted array, so for the best situation when the toSort vector is already sorted, the resoults are little weird..
for sort1 it's 12.234 and for sort2 is 0.0213..
For 10 000 elements sort1 is 982.069 and for sort2 is 0.2!
I have assertion for comparing if the vector is sorted.
I'm using newest mingw on Windows 7 and windows 8. For i7-5700 HQ and for i5-6300U..
It's only exercise for my to create something better, that have no implementation. I's all about my idea, so i don't want to use std::sort.
My question is:
Why second algorithm gives my ~0 time with 10 000 elements?
The first one has complexity of n² in any case.
Whereas in the sorted case, your second algorithm is linear:
toSort[minElem] < toSort[minElem - 1] and toSort[maxElem] > toSort[maxElem+1] is always false, so your inner loop break immediately.

Path finding in an undirected graph

I'm trying to list all the paths in an undirected graph, and my question is similar to this question. I've tried to run this code, but it loops indefinitely -- I ran it with 60 nodes. Any ideas on how to produce the correct solution?
I added such a random graph and the code is now like:
#include<stdio.h>
static struct {
int value1;
int value2;
int used;
} data[] = {
{ 1, 2 },
{ 1, 5 },
{ 2, 3 },
{ 2, 6 },
{ 3, 7 },
{ 4, 0 },
{ 0, 4 },
{ 7, 3 },
{ 2, 1 },
};
enum { DATA_SIZE = sizeof data / sizeof *data };
static int output[DATA_SIZE];
int traverse(int from, int to, int depth) {
output[depth++] = from;
int i;
if (from == to) {
for (i = 0; i < depth; i++) {
if (i) {
printf("-");
}
printf("%d", output[i]);
}
printf("\n");
} else {
for (i = 0; i < DATA_SIZE; i++) {
if (!data[i].used) {
data[i].used = 1;
if (from == data[i].value1) {
traverse(data[i].value2, to, depth);
} else if (from == data[i].value2) {
traverse(data[i].value1, to, depth);
}
data[i].used = 0;
}
}
}
}
int main() {
traverse(1, 7, 0);
}`
And the output is:
1-2-3-7
1-2-3-7
1-2-3-7
1-2-3-7
Why do I get that path 4 times? Is it possible to fix? thanks
You can not fix it. The number of paths in graph (not counting sparse graphs) is exponential by itself and only outputting will take forever. Clearly, it's impossible. Even if your graph is sparse (but connected) there will be at least O(N^2) paths.
As I understand the algorithm you link to, it will visit the same vertex multiple times (it will not visit the same edge multiple times, though). This means that the maximum length of one path is proportional to the number of edges in your graph, not the number of nodes. You say your graph has 60 nodes - how many edges? If that number is very large, then it may run for a very long time to produce even a single path.
You could modify the algorithm slightly to only visit each node once, but that may not be what you're looking for.