I'm making a program where I have a list of 34 cities and I am wanting to give each of these cities a probability of being chosen.
So I have:
vector<float> vec;
int s;
cin >> s;
srand(s);
for (int k=0; k < 34; k++)
{
float p1= (float)rand()/(float)((unsigned)RAND_MAX+1);
vec.push_back(p1);
}
So that gives each city a probability. The problem I am now having is I want to then do a random number generator that will choose two of these cities. So, for example city1 will have a 5%, city2 a 2%, city3, a 3%, etc. How can I randomly choose two of these cities based off the probabilities given?
I did this in genetic algorithm.
for your cities consider a line of 10 units.
now from 0-5 units on line are city1 6-7 for city2 and 8-9 for city3.
now choose a number at random from 0-9.
and found out in which cities range it comes in.
At first glance my solution will be :
Create a number equals to all city's probability
Create a random number, with max random number is equal to the previous number
Take the random number, and go throught your city vector and take the one who is corresponding.
Example :
City 1 : 5%
City 2 : 8%
City 3 : 2%
City 4 : 5%
City 5 : 12%
Create a number -> Number a = 32 (5+8+2+5+12)
Generate a number with : 1 <= number
Assume that the number is equal to 12
City 1 is choose if : 1 <= number <= 5 (So not)
City 2 is choose if : 6 <= number <= 13 (So yes)
City 2 is choose.
If you have any questions about that, you are welcome :)
Edit :
Well i will give you some more explaination.
Take this code :
for (int k=0; k < 10; k++)
{
float p1= (float)rand()/(float)((unsigned)RAND_MAX+1);
vec.push_back(p1);
}
Assume now that vec contain the following informations :
5
3
8
5
12
14
8
5
6
18
With each number correspond to the probability to choose a city.
5 -> 5% probability to choose (City1)
3 -> 3% probability to choose (City2)
8 -> 8% probability to choose (City3)
... etc
Now i will give you some code and i will explain it :
int nbReference = 0;
for (auto it = vec.begin() ; it != vec.end() ; ++it)
{
nbReference += *it;
}
nbReference = rand(nbReference);
int i = 0;
int cityProbability = 0;
for (auto it = vec.begin() ; it != vec.end() ; ++it)
{
cityProbability = *it;
if ((i + cityProbability) > nbReference)
{
return (i + 1);
}
i += cityProbability;
}
First i create a number equals to the addition of all city's probability
int nbReference = 0;
for (auto it = vec.begin() ; it != vec.end() ; ++it)
{
nbReference += *it;
}
Second, i generate a number that is respect the following range -> 0 < nbReference
Third, i create a loop that take all city one by one and quit when we got right city.
How does we know when a city is good?
Let's take an example!
With our previous probability
5 3 8 5 12 14 8 5 6 18
NbReference is equals to (5+3+8+5+12+14+8+5+6+18) so 84
To each city we are going to put a range equals to his probability plus all of previous city's probability. Let me show you :
5 -> Range 0 to 4 (0 to 4 = 5 ---> 5%)
3 -> Range 5 to 8 (5 to 8 = 3 ---> 3%)
8 -> Range 9 to 17
5 -> Range 18 to 22
... etc
If the number that we create here
nbReference = rand(nbReference);
Is in a city range, so that city is choosed.
Example : If the number is 16, city3 is choosed!
5 -> Range 0 to 4 Number is 16 so NOPE
3 -> Range 5 to 8 Number is 16 so NOPE
8 -> Range 9 to 17 Number is 16 so YES!
5 -> Range 18 to 22
... etc
Does is this helpfull? :)
Any questions? You are welcome
Maybe this code can help you (follows partially WhozCraig advice)
#include <iostream>
#include <random>
#include <algorithm>
int main(int argc, const char * argv[])
{
using namespace std::chrono;
system_clock::time_point tp = system_clock::now();
system_clock::duration dtn = tp.time_since_epoch();
std::default_random_engine generator(static_cast<int>(dtn.count()));
//Generate 34 cities
std::uniform_real_distribution<double> gen_distribution(0,1);
auto getProb = std::bind ( gen_distribution, generator );
std::vector<double> citiesProb;
double probSum(0.0);
double cityProb(0.0);
for (int k=0; k < 34; k++)
{
cityProb = getProb();
probSum += cityProb;
citiesProb.push_back(cityProb);
}
//Pick 7 cities
std::uniform_real_distribution<double> pick_distribution(0,probSum);
auto pickCity = std::bind ( pick_distribution, generator );
double chooseCity;
double probBasket;
for (int k=0; k < 7; ++k)
{
probBasket = 0.0;
chooseCity = pickCity();
for (int i = 0; i < citiesProb.size(); ++i)
{
if (chooseCity >= probBasket && chooseCity < probBasket + citiesProb[i])
{
std::cout << "City with index " << i << " picked" << std::endl;
}
probBasket += citiesProb[i];
}
}
return 0;
}
How it works:
city1 5%(0.05), city2 25%(0.25), city3 8%(0.08), city4 10%(0.1)
then
probSum = 0.05 + 0.25 + 0.08 + 0.1 = 0.48
then choose a number between 0 and 0.48 (named pickProb) and
if pickProb is between 0 and 0.05 pick city1 (prob = 0.05/0.48 = 10%)
if pickProb is between 0.05 and 0.30 pick city2 (prob = 0.25/0.48 = 52%)
if pickProb is between 0.30 and 0.38 pick city3 (prob = 0.08/0.48 = 16%)
if pickProb is between 0.38 and 0.48 pick city4 (prob = 0.1/0.48 = 20%)
if probSum = 1.0 then city1 is picked with probability 5%, city2 is picked with probability 25% and so on.
Related
I'm writing code that randomly generates a vector of indices, fetches a random one, then uses that index to fetch another index, and so on. However, my code seems to repeat a cycle of indices. Here is my full code:
vector<uint16_t>* genBuffer() {
vector<uint16_t>* buffer = new vector<uint16_t>(256);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distr(0, 255);
for (uint16_t i = 0; i < 256; i++) {
(*buffer)[i] = distr(gen);
}
shuffle(buffer->begin(), buffer->end(), gen);
return buffer;
}
double timeAccess(vector<uint16_t>* buff, uint64_t buffSize) {
struct timespec start, stop;
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distr(0, 255);
auto index = distr(gen);
auto nextIndex = (*buff)[index];
clock_gettime(CLOCK_MONOTONIC, &start);
for (uint64_t i = 0; i <= buffSize; i++) {
cout << nextIndex << endl;
nextIndex = (*buff)[nextIndex];
}
clock_gettime(CLOCK_MONOTONIC, &stop);
double time_taken = (stop.tv_sec - start.tv_sec) - (double)(stop.tv_nsec - start.tv_nsec);
double avgTime = time_taken/buffSize;
return avgTime;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
cout << "Please enter only one numerical argument." << endl;
return -1;
}
uint64_t buffSize = atoi(argv[1]);
auto randBuff = genBuffer();
auto timeTaken = timeAccess(randBuff, buffSize);
cout << "Average time per buffer read = " << timeTaken << " ns" << endl;
return 0;
}
Here is an example run with an argument of 25:
35
218
157
9
4
214
225
246
123
92
195
114
200
33
138
13
17
35
218
157
9
4
214
225
246
123
As you can see, the pattern eventually repeats, although it shouldn't do that.
This code is part of a cache benchmark I was asked to write for class. Here is the full code for anyone willing to try:
https://github.com/aabagdi/CacheBenchmark
As well, I'm trying to time the average time per read in ns. Am I doing that correctly? Thanks!
The generation of your traversal vector is flawed, and can easily generate loops. An example of what you're actually trying to generate for maximal traversal is similar to an interesting (albeit outdated) interview question concerning dropping a stack of bus tickets, each of which has a starting city, ending city, and as a city pair is unique among all others.
Consider holding four tickets, each of which goes from some city Sn to some other city Sm.
S4->S2
S1->S5
S3->S4
S5->S3
the proper order can be thought of like this:
S1->S5
S5->S3
S3->S4
S4->S2
The only difference here is that you need to get back from S2 to S1 if needed, since you don't really know where you're starting from. By adding one faux ticket, S2->S1, you can produce a maximal loop.
S1->S5
^ S5->S3
| S3->S4
| S4->S2
| S2->S1-\
| /
\----------------------
Now it doesn't matter where you start from; eventually you'll hit every city and be back where you started (to do it again if you want).
One way to do that is by building a pairing sequence, then patching in the final return-to-origin as a last step. First, n indexes, build an index array of values 0..(n-1).
// build index vector and shuffle
std::vector<uint16_t> idx(n);
std::iota(idx.begin(), idx.end(), 0);
std::mt19937 gen{ std::random_device{}() };
std::shuffle(idx.begin(), idx.end(), gen);
This is the rock on which we will build our church. We're going to traverse this random ordered sequence, and store the i+1'th index in the i'th slot of our final result. Like this:
// build chain
std::vector<uint16_t> result(n);
for (size_t i=0; i<(n-1); ++i)
result[idx[i]] = idx[i+1];
Finally, the last step is to link the last element of this chain to the initial element of the chain (wherever it is).
// set loop
result[idx[n-1]] = idx[0];
That's it. Now, it doesn't matter where you start in result, it will eventually lead to touching each index before returning to your starting point where it loops (maximally).
The full genBuffer looks like this:
std::vector<uint16_t> genBuffer(size_t n)
{
// build index vector and shuffle
std::vector<uint16_t> idx(n);
std::iota(idx.begin(), idx.end(), 0);
std::mt19937 gen{ std::random_device{}() };
std::shuffle(idx.begin(), idx.end(), gen);
// build chain
std::vector<uint16_t> result(n);
for (size_t i=0; i<(n-1); ++i)
result[idx[i]] = idx[i+1];
// set loop
result[idx[n-1]] = idx[0];
return result;
}
To prove this actually works, a simple test harness to generate a 32-element chain with a maximal loop.
int main()
{
auto randBuff = genBuffer(32);
// pick some random starting point.
std::mt19937 gen{ std::random_device{}() };
std::uniform_int_distribution<size_t> dist(0, randBuff.size()-1);
auto idx = dist(gen);
for (size_t i=0; i<randBuff.size(); ++i)
{
std::cout << idx << " -> " << randBuff[idx] << '\n';
idx = randBuff[idx];
}
}
Output (varies, obviously)
19 -> 10
10 -> 21
21 -> 12
12 -> 22
22 -> 28
28 -> 6
6 -> 16
16 -> 1
1 -> 7
7 -> 3
3 -> 27
27 -> 8
8 -> 14
14 -> 15
15 -> 17
17 -> 2
2 -> 9
9 -> 25
25 -> 31
31 -> 5
5 -> 18
18 -> 13
13 -> 29
29 -> 24
24 -> 26
26 -> 4
4 -> 20
20 -> 11
11 -> 0
0 -> 30
30 -> 23
23 -> 19
Note the last production leads to the first production.
In summary, your index vector generation is susceptible to loops. You want a loop, but only one and should be maximal. Doing what I showed above can give you that.
Couple of thoughts
your generate function will generate the same data each time since you do not seed your (p)rng
You randomly pick an entry and then follow the links, why wouldnt there be a loop? WHy not simply print them out and see if there is a loop.
I mean your generate function can create in the list
1,2,3,0
Thats a loop
let say I have a total number
tN = 12
and a set of elements
elem = [1,2,3,4]
and a prob for each element to be taken
prob = [0.0, 0.5, 0.75, 0.25]
i need to get a random multiset of these elements, such as
the taken elements reflects the prob
the sum of each elem is tN
with the example above, here's some possible outcome:
3 3 2 4
2 3 2 3 2
3 4 2 3
2 2 3 3 2
3 2 3 2 2
at the moment, maxtN will be 64, and elements the one above (1,2,3,4).
is this a Knapsack problem? how would you easily resolve it? both "on the fly" or "pre-calculate" approch will be allowed (or at least, depends by the computation time). I'm doing it for a c++ app.
Mission: don't need to have exactly the % in the final seq. Just to give more possibility to an elements to be in the final seq due to its higher prob. In few words: in the example, i prefer get seq with more 3-2 rather than 4, and no 1.
Here's an attempt to select elements with its prob, on 10 takes:
Randomizer randomizer;
int tN = 12;
std::vector<int> elem = {2, 3, 4};
std::vector<float> prob = {0.5f, 0.75f, 0.25f};
float probSum = std::accumulate(begin(prob), end(prob), 0.0f, std::plus<float>());
std::vector<float> probScaled;
for (size_t i = 0; i < prob.size(); i++)
{
probScaled.push_back((i == 0 ? 0.0f : probScaled[i - 1]) + (prob[i] / probSum));
}
for (size_t r = 0; r < 10; r++)
{
float rnd = randomizer.getRandomValue();
int index = 0;
for (size_t i = 0; i < probScaled.size(); i++)
{
if (rnd < probScaled[i])
{
index = i;
break;
}
}
std::cout << elem[index] << std::endl;
}
which gives, for example, this choice:
3
3
2
2
4
2
2
4
3
3
Now i just need to build a multiset which sum up to tN. Any tips?
A number is called a stepping number if all adjacent digits in the number have an absolute difference of 1.
Examples of stepping numbers :- 0,1,2,3,4,5,6,7,8,9,10,12,21,23,...
I have to generate stepping numbers upto a given number N. The numbers generated should be in order.
I used the simple method of moving over all the numbers upto N and checking if it is stepping number or not. My teacher told me it is brute force and will take more time. Now, I have to optimize my approach.
Any suggestions.
Stepping numbers can be generated using Breadth First Search like approach.
Example to find all the stepping numbers from 0 to N
-> 0 is a stepping Number and it is in the range
so display it.
-> 1 is a Stepping Number, find neighbors of 1 i.e.,
10 and 12 and push them into the queue
How to get 10 and 12?
Here U is 1 and last Digit is also 1
V = 10 + 0 = 10 ( Adding lastDigit - 1 )
V = 10 + 2 = 12 ( Adding lastDigit + 1 )
Then do the same for 10 and 12 this will result into
101, 123, 121 but these Numbers are out of range.
Now any number transformed from 10 and 12 will result
into a number greater than 21 so no need to explore
their neighbors.
-> 2 is a Stepping Number, find neighbors of 2 i.e.
21, 23.
-> generate stepping numbers till N.
The other stepping numbers will be 3, 4, 5, 6, 7, 8, 9.
C++ code to do generate stepping numbers in a given range:
#include<bits/stdc++.h>
using namespace std;
// Prints all stepping numbers reachable from num
// and in range [n, m]
void bfs(int n, int m)
{
// Queue will contain all the stepping Numbers
queue<int> q;
for (int i = 0 ; i <= 9 ; i++)
q.push(i);
while (!q.empty())
{
// Get the front element and pop from the queue
int stepNum = q.front();
q.pop();
// If the Stepping Number is in the range
// [n, m] then display
if (stepNum <= m && stepNum >= n)
cout << stepNum << " ";
// If Stepping Number is 0 or greater than m,
// need to explore the neighbors
if (stepNum == 0 || stepNum > m)
continue;
// Get the last digit of the currently visited
// Stepping Number
int lastDigit = stepNum % 10;
// There can be 2 cases either digit to be
// appended is lastDigit + 1 or lastDigit - 1
int stepNumA = stepNum * 10 + (lastDigit- 1);
int stepNumB = stepNum * 10 + (lastDigit + 1);
// If lastDigit is 0 then only possible digit
// after 0 can be 1 for a Stepping Number
if (lastDigit == 0)
q.push(stepNumB);
//If lastDigit is 9 then only possible
//digit after 9 can be 8 for a Stepping
//Number
else if (lastDigit == 9)
q.push(stepNumA);
else
{
q.push(stepNumA);
q.push(stepNumB);
}
}
}
//Driver program to test above function
int main()
{
int n = 0, m = 99;
// Display Stepping Numbers in the
// range [n,m]
bfs(n,m);
return 0;
}
Visit this link.
The mentioned link has both BFS and DFS approach.
It will provide you with explaination and code in different languages for the above problem.
We also can use simple rules to move to the next stepping number and generate them in order to avoid storing "parents".
C.f. OEIS sequence
#include <iostream>
int next_stepping(int n) {
int left = n / 10;
if (left == 0)
return (n + 1); // 6=>7
int last = n % 10;
int leftlast = left % 10;
if (leftlast - last == 1 & last < 8)
return (n + 2); // 32=>34
int nxt = next_stepping(left);
int nxtlast = nxt % 10;
if (nxtlast == 0)
return (nxt * 10 + 1); // to get 101
return (nxt * 10 + nxtlast - 1); //to get 121
}
int main()
{
int t = 0;
for (int i = 1; i < 126; i++, t = next_stepping(t)) {
std::cout << t << "\t";
if (i % 10 == 0)
std::cout << "\n";
}
}
0 1 2 3 4 5 6 7 8 9
10 12 21 23 32 34 43 45 54 56
65 67 76 78 87 89 98 101 121 123
210 212 232 234 321 323 343 345 432 434
454 456 543 545 565 567 654 656 676 678
765 767 787 789 876 878 898 987 989 1010
1012 1210 1212 1232 1234 2101 2121 2123 2321 2323
2343 2345 3210 3212 3232 3234 3432 3434 3454 3456
4321 4323 4343 4345 4543 4545 4565 4567 5432 5434
5454 5456 5654 5656 5676 5678 6543 6545 6565 6567
6765 6767 6787 6789 7654 7656 7676 7678 7876 7878
7898 8765 8767 8787 8789 8987 8989 9876 9878 9898
10101 10121 10123 12101 12121
def steppingNumbers(self, n, m):
def _solve(v):
if v>m: return 0
ans = 1 if n<=v<=m else 0
last = v%10
if last > 0: ans += _solve(v*10 + last-1)
if last < 9: ans += _solve(v*10 + last+1)
return ans
ans = 0 if n>0 else 1
for i in range(1, 10):
ans += _solve(i)
return ans
I have a word corpus of say 3000 words such as [hello, who, this ..].
I want to find the nth 3 word combination from this corpus.I am fine with any order as long as the algorithm gives consistent output.
What would be the time complexity of the algorithm.
I have seen this answer but was looking for something simple.
(Note that I will be using 1-based indexes and ranks throughout this answer.)
To generate all combinations of 3 elements from a list of n elements, we'd take all elements from 1 to n-2 as the first element, then for each of these we'd take all elements after the first element up to n-1 as the second element, then for each of these we'd take all elements after the second element up to n as the third element. This gives us a fixed order, and a direct relation between the rank and a specific combination.
If we take element i as the first element, there are (n-i choose 2) possibilities for the second and third element, and thus (n-i choose 2) combinations with i as the first element. If we then take element j as the second element, there are (n-j choose 1) = n-j possibilities for the third element, and thus n-j combinations with i and j as the first two elements.
Linear search in tables of binomial coefficients
With tables of these binomial coefficients, we can quickly find a specific combination, given its rank. Let's look at a simplified example with a list of 10 elements; these are the number of combinations with element i as the first element:
i
1 C(9,2) = 36
2 C(8,2) = 28
3 C(7,2) = 21
4 C(6,2) = 15
5 C(5,2) = 10
6 C(4,2) = 6
7 C(3,2) = 3
8 C(2,2) = 1
---
120 = C(10,3)
And these are the number of combinations with element j as the second element:
j
2 C(8,1) = 8
3 C(7,1) = 7
4 C(6,1) = 6
5 C(5,1) = 5
6 C(4,1) = 4
7 C(3,1) = 3
8 C(2,1) = 2
9 C(1,1) = 1
So if we're looking for the combination with e.g. rank 96, we look at the number of combinations for each choice of first element i, until we find which group of combinations the combination ranked 96 is in:
i
1 36 96 > 36 96 - 36 = 60
2 28 60 > 28 60 - 28 = 32
3 21 32 > 21 32 - 21 = 11
4 15 11 <= 15
So we know that the first element i is 4, and that within the 15 combinations with i=4, we're looking for the eleventh combination. Now we look at the number of combinations for each choice of second element j, starting after 4:
j
5 5 11 > 5 11 - 5 = 6
6 4 6 > 4 6 - 4 = 2
7 3 2 <= 3
So we know that the second element j is 7, and that the third element is the second combination with j=7, which is k=9. So the combination with rank 96 contains the elements 4, 7 and 9.
Binary search in tables of running total of binomial coefficients
Instead of creating a table of the binomial coefficients and then performing a linear search, it is of course more efficient to create a table of the running total of the binomial coefficient, and then perform a binary search on it. This will improve the time complexity from O(N) to O(logN); in the case of N=3000, the two look-ups can be done in log2(3000) = 12 steps.
So we'd store:
i
1 36
2 64
3 85
4 100
5 110
6 116
7 119
8 120
and:
j
2 8
3 15
4 21
5 26
6 30
7 33
8 35
9 36
Note that when finding j in the second table, you have to subtract the sum corresponding with i from the sums. Let's walk through the example of rank 96 and combination [4,7,9] again; we find the first value that is greater than or equal to the rank:
3 85 96 > 85
4 100 96 <= 100
So we know that i=4; we then subtract the previous sum next to i-1, to get:
96 - 85 = 11
Now we look at the table for j, but we start after j=4, and subtract the sum corresponding to 4, which is 21, from the sums. then again, we find the first value that is greater than or equal to the rank we're looking for (which is now 11):
6 30 - 21 = 9 11 > 9
7 33 - 21 = 12 11 <= 12
So we know that j=7; we subtract the previous sum corresponding to j-1, to get:
11 - 9 = 2
So we know that the second element j is 7, and that the third element is the second combination with j=7, which is k=9. So the combination with rank 96 contains the elements 4, 7 and 9.
Hard-coding the look-up tables
It is of course unnecessary to generate these look-up tables again every time we want to perform a look-up. We only need to generate them once, and then hard-code them into the rank-to-combination algorithm; this should take only 2998 * 64-bit + 2998 * 32-bit = 35kB of space, and make the algorithm incredibly fast.
Inverse algorithm
The inverse algorithm, to find the rank given a combination of elements [i,j,k] then means:
Finding the index of the elements in the list; if the list is sorted (e.g. words sorted alphabetically) this can be done with a binary search in O(logN).
Find the sum in the table for i that corresponds with i-1.
Add to that the sum in the table for j that corresponds with j-1, minus the sum that corresponds with i.
Add to that k-j.
Let's look again at the same example with the combination of elements [4,7,9]:
i=4 -> table_i[3] = 85
j=7 -> table_j[6] - table_j[4] = 30 - 21 = 9
k=9 -> k-j = 2
rank = 85 + 9 + 2 = 96
Look-up tables for N=3000
This snippet generates the look-up table with the running total of the binomial coefficients for i = 1 to 2998:
function C(n, k) { // binomial coefficient (Pascal's triangle)
if (k < 0 || k > n) return 0;
if (k > n - k) k = n - k;
if (! C.t) C.t = [[1]];
while (C.t.length <= n) {
C.t.push([1]);
var l = C.t.length - 1;
for (var i = 1; i < l / 2; i++)
C.t[l].push(C.t[l - 1][i - 1] + C.t[l - 1][i]);
if (l % 2 == 0)
C.t[l].push(2 * C.t[l - 1][(l - 2) / 2]);
}
return C.t[n][k];
}
for (var total = 0, x = 2999; x > 1; x--) {
total += C(x, 2);
document.write(total + ", ");
}
This snippet generates the look-up table with the running total of the binomial coefficients for j = 2 to 2999:
for (var total = 0, x = 2998; x > 0; x--) {
total += x;
document.write(total + ", ");
}
Code example
Here's a quick code example, unfortunately without the full hardcoded look-up tables, because of the size restriction on answers on SO. Run the snippets above and paste the results into the arrays iTable and jTable (after the leading zeros) to get the faster version with hard-coded look-up tables.
function combinationToRank(i, j, k) {
return iTable[i - 1] + jTable[j - 1] - jTable[i] + k - j;
}
function rankToCombination(rank) {
var i = binarySearch(iTable, rank, 1);
rank -= iTable[i - 1];
rank += jTable[i];
var j = binarySearch(jTable, rank, i + 1);
rank -= jTable[j - 1];
var k = j + rank;
return [i, j, k];
function binarySearch(array, value, first) {
var last = array.length - 1;
while (first < last - 1) {
var middle = Math.floor((last + first) / 2);
if (value > array[middle]) first = middle;
else last = middle;
}
return (value <= array[first]) ? first : last;
}
}
var iTable = [0]; // append look-up table values here
var jTable = [0, 0]; // and here
// remove this part when using hard-coded look-up tables
function C(n,k){if(k<0||k>n)return 0;if(k>n-k)k=n-k;if(!C.t)C.t=[[1]];while(C.t.length<=n){C.t.push([1]);var l=C.t.length-1;for(var i=1;i<l/2;i++)C.t[l].push(C.t[l-1][i-1]+C.t[l-1][i]);if(l%2==0)C.t[l].push(2*C.t[l-1][(l-2)/2])}return C.t[n][k]}
for (var iTotal = 0, jTotal = 0, x = 2999; x > 1; x--) {
iTable.push(iTotal += C(x, 2));
jTable.push(jTotal += x - 1);
}
document.write(combinationToRank(500, 1500, 2500) + "<br>");
document.write(rankToCombination(1893333750) + "<br>");
So I'm trying to use a modified Bellman Ford algorithm to find the shortest path from the starting vertex to the ending vertex but I cannot go over a certain distance. So given a graph with edges:
0 1 100 30
0 4 125 50
1 2 50 250
1 2 150 50
4 2 100 40
2 3 90 60
4 3 125 150
Where the each line represents an edge and the first value is the starting vertex, the second value is the end vertex, the third is cost and the fourth is the distance.
With the code I have now when I try to find the cheapest path from 0 to 3 without going over 140 it yields 0 (default when no path is found) instead of 340 (the cost of the cheapest path). Any suggestions on how to alter my code.
Just gonna copy the code down below because this site is not letting me do anything else.
static void BellmanFord(struct Graph *graph, int source, int ending, int max){
int edges = graph->edgeCount;
int vertices = graph->verticesCount;
int* money = (int*)malloc(sizeof(int) * vertices);
int* distance = (int*)malloc(sizeof(int) * vertices);
for (int I = 0; I < vertices; I++){
distance[I] = INT_MAX;
money[I] = INT_MAX;
}
distance[source] = 0;
money[source] = 0;
for (int I = 1; I <= vertices - 1; ++I){
for int j = 0; j < edges; ++j){
int u = graph->edge[j].Source;
int v = graph->edge[j].Destination;
int Cost = graph->edge[j].cost;
int Duration = graph->edge[j].duration;
if ((money[u] != INT_MAX) && (money[u] + Cost < money[v])){
if (distance[u] + Duration <= max){
money[v] = money[u] + Cost;
distance[v] = distance[u] + Duration;
}
}
}
}
if (money[ending] == INT_MAX) cout << "0" << endl;
else cout << money[ending] << endl;
}
Please help! This is probably not that hard but finals are stressing me out
This problem, known as the "constrained shortest path" problem, is much harder to solve than this. The algorithm you provided does not solve it, it only might catch the solution, only by luck, according to the graph's structure.
When this algorithm is applied on the graph you provide, with max-distance = 140, it fails to find the solution, which is 0-->1-->2-->3 (using the edge 1 2 150 50) with total cost of 340 and a distance of 140.
We can observe the reason of failure by logging the updates to the nodes whenever they are updated, and here is the result:
from node toNode newCost newDistance
0 1 100 30
0 4 125 50
1 2 250 80
4 2 225 90
Here the algorithm is stuck and cannot go further, since any progress from this point will lead to paths that exceed the max distance (of 140). As you see, node 2 has found the path 0-->4--2 which is the lowest-cost from node 0 while respecting the max-distance constraint. But now, any progress from 2 to 3 will exceed the distance of 140 (it will be 150, because 2->3 has a distance of 60.)
Running again with max-distance=150 will find the path 0-->4->3 with cost 315 and distance 150.
from node toNode newCost newDistance
0 1 100 30
0 4 125 50
1 2 250 80
4 2 225 90
2 3 315 150
Obviously this is not the minimum cost path that respects the constraint of distance; the correct should be the same (that it failed to find) in the first example. This again proves the failure of the algorithm; this time it gives a solution but which is not the optimal one.
In conclusion, this is not a programming mistake or bug in the code, it is simply that the algorithm is not adequate to the stated problem.
Okay so right before the
if (money[ending] == INT_MAX) cout << "0" << endl;
I added some code that made it work but I'm wondering will this work for every case or does it need to be altered a little.
if (money[ending] == INT_MAX){
for (int j = 0; j < edges; ++j){
int u = graph->edge[j].Source;
int v = graph->edge[j].Destination;
int Cost = graph->edge[j].cost;
int Duration = graph->edge[j].duration;
if ((distance[u] != INT_MAX) && (distance[u] +Duration < distance[v])){
if (distance[u] + Duration <= max){
money[v] = money[u] + Cost;
distance[v] = distance[u] + Duration;
}
}
}
}