Shortest Path Algorithm C++ Dijkstra's With Layover Included - c++

Good morning everyone,
I have a problem where I have to calculate the shortest path (including layovers) from one train station to another. I usually don't ask for help but I am very stuck on this one. I started out by writing a standard dijkstra's algorithm and thought I could modify it for the layovers but that hasn't been the case. The program is set up as an adjacency matrix of [stationCount][stationCount] size made of edge structures. Each edge structure has an:
int departure; int arrival; int totalTime; (arrival - departure)
and all of the times are in military time (0900, 1230, etc.). The method I am having issues with is posted below and I am fairly certain my issues are with calculating/adding in the layovers. I have commented that section to mark it.
Lastly, this is the input data I am with:
1 2 0430 0600
1 4 0550 1000
2 4 0630 1100
2 5 1130 1300
3 1 1245 1500
3 6 0300 0530
4 5 0730 0945
4 7 1145 1600
4 6 1500 1900
4 3 1000 1330
5 7 1430 1730
7 6 1550 1800
I have asked the program to try to return the shortest path from (1, 6) but it is not returning the valid path. The shortest path as I have calculated it would be 1->4 (0450) + (0500) -layover + 4->6 (0400) = (1350) which I could then convert to 13 hours 10 minutes. There are multiple other paths it could take but all of them start earlier and end at the same time or later making them longer paths. If anyone has any guidance on what I am doing wrong or of a better way to do this please let me know. Thank you.
int TRAINS::dijkstra(int source, int destination)
{
vector <bool> vertexSet;
int distance[stationCount];
int minNode, minDistance, source, destination, count = 0, previousNode;
for(int i = 1; i < stationCount; ++i)
{
distance[i] = INFINITY;
vertexSet.push_back(false);
}
distance[source] = 0;
while((!empty(vertexSet)) && count < stationCount - 1)
{
count++;
minNode = INFINITY;
minDistance = INFINITY;
for(int vertex = 1; vertex < stationCount; ++vertex)
{
if(vertexSet[vertex] == false && distance[vertex] <= minDistance)
{
minDistance = distance[vertex];
minNode = vertex;
}
}
vertexSet[minNode] = true;
//so what i tried to do is that if it is the first time running through (i.e. source == minNode then it will set the distance for all verteces to .totalTime (the regular weight) and that seems to work
for(int vertex = 1; vertex < stationCount; ++vertex)
{
if(vertexSet[vertex] == false && matrix[minNode][vertex].arrival > 0)
{
if(minNode == source)
{
if(distance[minNode] != INFINITY && matrix[minNode][vertex].totalTime < distance[vertex])
{
distance[vertex] = matrix[minNode][vertex].totalTime;
if(vertex == destination)
{
return distance[vertex];
}
}
}
//then here if it wasn't the first time (this is where I am having trouble... i was trying to have it take the current departure time - the previous arrival time to calculate the layover and then add it to the current distance (distance[minNode]) plush the actual weight still... but somewhere this is going wrong and i am not getting the right output.
else
{
if(distance[minNode] != INFINITY && matrix[minNode][vertex].departure > 0 && matrix[minNode][vertex].departure - matrix[previousNode][minNode].arrival + matrix[minNode][vertex].totalTime + distance[minNode] < distance[vertex])
{
distance[vertex] = matrix[minNode][vertex].departure - matrix[previousNode][minNode].arrival + matrix[minNode][vertex].totalTime + distance[minNode];
}
if(vertex == destination)
{
return distance[vertex];
}
}
}
}
//before the next cycle i set the current minNode to previous for use in the next cycle
previousNode = minNode;
}
return -1;
}
-

Related

Contiguous sub sequence with max success rate in a sequence given a minimum sub sequence length

I'm trying to solve an algorithmic problem where the premises revolves around an input sequence that consists of 0s and 1s along with a minimum length l for the output subsequence. The problem asks for the subsequence which has the highest rate of 1s (number of ones in the subsequence divided by the length of the subsequence). Further background and sample input/output to the problem can be found here.
I have come up with a solution that passes all tests except for the last one and I am trying to figure out what my current implementation is lacking. My approach is to use a dynamically resizeable sliding window while storing the maximum rate of the sliding window along with the length of that maximum rated window. I think the way that I'm moving (growing and shrinking) my window is the problem, but I'm having trouble figuring out what to change.
This is how I move my window:
static void max_rate(long min_len, string sequence) {
long left_window = 0, right_window = min_len - 1;
long best_left = 0, best_len = 0, most_ones = 0;
long double best_success_rate = -1;
for (;;) {
auto tmp = sequence.substr(left, right - left + 1);
long n_ones = count_ones(tmp);
long double success_rate = (long double)n_ones / (long double)tmp.length();
if (success_rate >= best_success_rate) {
best_success_rate = success_rate;
best_left = left;
best_len = right - left + 1;
most_ones = n_ones;
}
// Window sliding starts here
bool can_move_right = (right + 1) < (long)sequence.length();
bool can_move_left = (right - left + 1 - 1) >= min_len;
if (can_move_right && sequence.at(right + 1) == '1') {
++(right);
} else if (can_move_right && sequence.at(right + 1) == '1') {
++(right);
} else if (can_move_left && (sequence.at(left + 1) == '0')) {
++left;
} else if (can_move_right) {
++(right);
} else {
break;
}
cout << best_left + 1 << " ";
cout << best_len << endl;
I'm basically checking:
Grow the window if you can increase the rate
Otherwise, if possible (considering our minimum size requirement), shrink the window if you can increase the rate
Otherwise, if possible (-), shrink the window
Otherwise, if possible (we are not at the end of the sequence) grow the window
I must be missing something here I think
According to the code you posted, for input
8, "0011101011"
the sequence would seem to be
0 0 1 1 1 0 1 0 1 1
l r
l r
l r
l r
which gives us:
zero-based index 1, interval length 9
and ratio 6 / 9 = 0.6666666666666666
but the correct answer is
ratio 0.75
zero-based index 2, interval length 8

Finding running low

I have a vector of structs containing the following type of variables:
Date Time Low
11/1/17 929 74.25
11/1/17 930 73
11/1/17 931 75
11/1/17 932 70
etc.
I now want to add another struct to my vector called "LowRun", where LowRun is the smallest low at every point in the iteration, like so:
Date Time Low LowRun
11/1/17 929 74.25 74.25
11/1/17 930 73 73
11/1/17 931 75 73
11/1/17 932 70 70
This is what I've tried so far, but this is not giving the right output:
edited:
int CalcLow_SoFar(std::vector<PriceInfo>& p)
double running_low = p[0].Low;
for (size_t i = 1; i < p.size(); ++i)
{
if (p[i].Time > 929
&& p[i].Time < 1601
&& p[i].Date == p[i - 1].Date)
{
if (p[i].Low < running_low)
{
running_low = p[i].Low;
p[i].LowRun = running_low;
}
}
}
return 0;
}
Can you help me get unstuck, thank you!
You've got several weird logic problems in your code, so I'm just going to list them here.
This if statement makes no sense: if (p[i].Low < p[i-1].Low). You assign running_low to the current value whenever the current value is less than the previous value. However, it's perfectly possible for the value to decrease while not being lower than the running low. For example, if you have the sequence 1, 3, 2, the LowRun value at the index 2 gets assigned to 2 because 2 is less than 3, even though the running low should be 1.
The if statement after the one I was talking about (if (p[i+1].Low < running_low)) would have been good if you didn't add 1 to i for some reason. Instead of going from 1 to p.size() - 1, you're now going from 2 to p.size(), so you access one element past the end of the vector which is undefined behavior.
You only assigned the LowRun values when the running_low value changes. This means that if a value didn't change the running low, it's LowRun value is uninitialized which is where the garbage values come from.
You didn't initialize running_low to the first element.
I don't know the details of what you're doing, but the condition checking the time and date looks suspicious, so I've removed it for now. It basically ignores an entry if it's the first one on that day. If that's what you want to do, instead of initializing running_low to the value of the first element, initialize it to something like std::numeric_limits<double>::max() so it's guaranteed to get updated on the first valid entry and change your loop to start from 0.
This doesn't affect the functionality, but unlike main(), other functions you define don't have to return an int or even anything at all. Use void if you don't need the function to return anything.
Lastly, you should get in the habit of using good formatting including proper indents so you don't confuse yourself.
The fixed code:
void CalcLow_SoFar(std::vector<PriceInfo>& p)
{
double running_low = p[0].Low;
p[0].LowRun = p[0].Low;
for (size_t i = 1; i < p.size(); ++i)
{
if (p[i].Low < running_low)
{
running_low = p[i].Low;
}
p[i].LowRun = running_low;
}
}
Version with the date and time checks:
void CalcLow_SoFar(std::vector<PriceInfo>& p)
{
double running_low = std::numeric_limits<double>::max();
for (size_t i = 0; i < p.size(); ++i)
{
if (p[i].Time > 929
&& p[i].Time < 1601
&& i != 0
&& p[i].Date == p[i - 1].Date
&& p[i].Low < running_low)
{
running_low = p[i].Low;
}
p[i].LowRun = running_low;
}
}
Note that for this version, the Low values for the first few elements will be a very large value since a valid entry hasn't been encountered and running_low still holds the value we initialized it to.
Here's the version which only includes the values from the same day in the running low and also ignores any values with a time not in [930, 1600]:
void CalcLow_SoFar(std::vector<PriceInfo>& p)
{
double running_low;
for (size_t i = 0; i < p.size(); ++i)
{
if (i == 0 || p[i].Date != p[i - 1].Date)
{
running_low = std::numeric_limits<double>::max();
}
if (p[i].Time >= 930
&& p[i].Time <= 1600
&& p[i].Low < running_low)
{
running_low = p[i].Low;
}
p[i].LowRun = running_low;
}
}
Similar to the second version in this answer, the LowRun values might be std::numeric_limits<double>::max() if a value in that day within the time limits hasn't been encountered yet.

count consecutive 1's in binary

I am writing code in Hackerrank. And recently the problem said, convert decimal to base 2 and then count the max consecutive 1's in the binary number. And first I come with following solution. It works fine. But I do not understand the counting part of it, even though I wrote it.
The code is
int main(){
int n,ind=0, count=0, mmax=0;
char bin[100];
cin >> n;
while(n){
if(n%2==0) {
bin[ind]='0';
n = n / 2;
ind = ind + 1;
}
else if(n%2==1) {
bin[ind]='1';
n = n / 2;
ind = ind + 1;
}
}
for(int i=0; i<=(ind-1); i++){
if(bin[i] == '1' && bin[i+1] == '1'){
count++;
if(mmax < count)
mmax = count;
}
else
count=0;
}
cout << mmax + 1 << endl;
return 0;
}
In the above code, I guess that variable mmax will give me the max consecutive number of 1's but it gives me value that has (max consecutive - 1), So I just wrote like that and submitted the code. But I am curious about. why it is working that way. I am little bit of confused the way that code works like this.
Thanks
Lets say you have this binary sequence:
11110
Your code will compare starting from the first and second:
|11|110 1 && 1 -> max = 1
1|11|10 1 && 1 -> max = 2
11|11|0 1 && 1 -> max = 3
111|10| 1 && 0 -> max = 3
you can see, that although there are 4 1's you only do 3 comparisons, so your max will always be -1 of the actual max. You can fix this by adding mmax += 1 after your for loop.
Just a little bit of trace using small example will show why.
First, lets say there is only 1 '1' in your array.
Since you require both the current position and your next position to be '1', you will always get 0 for this case.
Let's say I have "11111". At the first '1', since next position is also '1', you increment count once. This repeats until 4th '1' and you increment your count 4 times in total so far. When you reach 5th '1', your next position is not '1', thus your count stops at 4.
In general, your method is like counting gaps between fingers, given 5 fingers, you get 4 gaps.
Side note: your code will fail for the case when there is no '1' in your array.

A program that takes in a matrix and outputs the fastest path to the "exit" and the number it takes to get there

So I'm having a lot of trouble understanding c++ again I've taken my programming class twice and failed. I need help. I'm not interested in programming anymore because it's obviously not for me. I just need to pass. Here's the problem:
The goal of this assignment is to practice recursive algorithms by writing a program that takes in a matrix representing the number of guards in each room of the castle and outputs the fastest path to the princess and the number of guards you will have to fight.
You're moving through a map(array) that looks like:
5 5
6 2 3 44 15
1 7 2 9 10
11 1 5 14 12
5 17 2 1 20
21 7 33 4 25
Where the first to numbers are the size of your array and you can only move right and down.
So an output would be:
50 > > v v v > v >
We're given a skeleton which we have to fill in but I don't know what some of it does and it might be too long to copy and paste here, I'm new to the community.
How would you tackle this assignment
Using recursion you try to simplify the problem. So take a step right, compute the score for this step and add it to the rest of the solution by calling the same function on a smaller matrix (leaving out the left column). Then take a step down and do the same with the smaller matrix leaving out the top row. Then choose the solution with the lowest score.
This is just a dynamic programming problem.
I don't know how to pass a 2-d array as a function parameter.
Someone correct me please(How to pass 'matrix' array and 'result' array as function parameters). Rest all part is fine
Algorithm is simple. Just start from the last position and come backwards.
where result[i][j] = min(result[i+1][j],result[i][j+1])
void function(int a,int b,int** matrix,int** result){
if(result[a+1][b] == -1 && result[a][b+1] == -1){
result[a][b] = min(function(a+1,b,matrix,result),function(a,b+1,matrix,result));
}
else if(result[a+1][b] == -1 && result[a][b+1] != -1){
result[a][b] = min(function(a+1,b,matrix,result),result[a][b+1]);
}
else if(result[a+1][b] != -1 && result[a][b+1] == -1){
result[a][b] = min(result[a+1][b],function(a,b+1,matrix,result));
}
return;
}
int main(){
int p,q;
cin>>p>>q;
int matrix[p][q];
for(int i=0;i<p;i++){
for(int j=0;j<q;j++){
cin>>matrix[i][j];
}
}
int result[p][q];
for(int i=0;i<p;i++){
for(int j=0;j<q;j++){
result[i][j] = -1;
}
}
result[p-1][q-1] = matrix[p-1][q-1];
for(int i=q-2;i>=0;i++){
result[p-1][i] = matrix[p-1][i] + result[p-1][i+1];
}
for(int i=p-2;i>=0;i++){
result[i][q-1] = matrix[i][q-1] + result[i+1][q-1];
}
function(0,0,matrix,result);
cout<<results[0][0]<<endl;
}

How to improve upon this?

There are n groups of friends staying in the queue in front of bus station. The i-th group consists of ai men. Also, there is a single bus that works on the route. The size of the bus is x, that is it can transport x men simultaneously.
When the bus comes (it always comes empty) to the bus station, several groups from the head of the queue goes into the bus. Of course, groups of friends don't want to split, so they go to the bus only if the bus can hold the whole group. In the other hand, none wants to lose his position, that is the order of groups never changes.
The question is: how to choose the size x of the bus in such a way that the bus can transport all the groups and everytime when the bus moves off the bus station there is no empty space in the bus (the total number of men inside equals to x)?
Input Format:
The first line contains the only integer n (1≤n≤10^5). The second line contains n space-separated integers a1,a2,…,an (1≤ai≤10^4).
Output Format:
Print all the possible sizes of the bus in the increasing order.
Sample:
8
1 2 1 1 1 2 1 3
Output:
3 4 6 12
I made this code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void)
{
int max=0,sum=0,i,n;
cin>>n;
int values[100000];
for ( i = 0; i < n; i++ )
{
cin>>values[i];
sum = sum + values[i];
if ( values[i] > max )
max = values[i];
}
int p = 0,j;
int count = 0;
vector<int> final;
for ( i = 0; i < n; i++ )
{
p = p + values[i];
j = 0;
if ( p >= max && sum%p == 0)
{
flag = 0;
while ( j < n )
{
garb = p;
while (garb!= 0)
{
garb = garb - values[j++];
if ( garb < 0 )
flag = 1;
}
}
if ( flag == 0 )
{
final.push_back(p);
count++;
}
}
}
sort(final.begin(),final.end());
for ( j = 0; j < count; j++ )
{
cout<<final[j]<<"\t";
}
return 0;
}
Edit: I did this in which basically, I am checking if the found divisor satisfies the condition, and if at any point of time, I get a negative integer on taking difference with the values, I mark it by using a flag. However, it seems to give me a seg fault now. Why?
I firstly, calculated the maximum value out of the all possible values, and then, I checked if its a divisor of the sum of the values. However, this approach doesn't work for the input as:
10
2 2 1 1 1 1 1 2 1 2
My output is
2 7 14
whereas the output should be
7 14
only.
Any other approach that I can go with?
Thanks!
I can think of the following simple solution (since your present concern is correctness and not time complexity):
Calculate the sum of all ai's (as you are already doing).
Calculate the maximum of all ai's (as you are already doing).
Find all the factors of sum that are > max(ai).
For each factor, iterate through the ai's and check whether the bus condition is satisfied.