Algorithm/Function about computing taxi fare [closed] - algorithm

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Let's say that a taxi charges $3.10 for the first fifth of a mile. Then for each additional fifth of a mile it charges half a dollar. For every minute of waiting or delay it charges half a dollar. However, this delay charge is applied instead of the mileage charge for each minute during which the speed of the taxi is slower than the brea-even point. The break-even point is the speed at which a fifth of a mile is driven in one minute. We are assuming the taxi goes at constant speed.
I am trying to write an algorithm or function that takes in the total distance and total time travelled by taxi and outputs the fare. However, I am having difficulty factoring in the delay charge.
So if the taxi is going at constant speed then ideally it would travel x miles during the time given (constant speed * time interval).
If we subtract the actual miles travelled from this value, we would get the number of "wasted" miles that could have been travelled but were not.
And then I lose the train of thought and I am not sure where to go from there. Any help/hint would be appreciated.

There is no single output to this problem when given only total_time and total_distance. I will
show two instances resulting in same total_time and total_distance but different total fares.
Instance 1:
1st min: travels 0.4 mile; fare = 3.1+0.5 = 3.6
2nd min: waits at signal; fare = 0.5 for waiting a min at speed less than break even point
3rd min: travels 0.8 mile; fare = 0.5*4 = 2
total_fare = 3.6 + 0.5 + 2 = 6.1
Instance 2:
1st min: travels 0.4 mile; fare = 3.1+0.5 = 3.6
3rd min: travels 0.4 mile; fare = 0.5*2 = 1
3rd min: travels 0.4 mile; fare = 0.5*2 = 1
total_fare = 3.6 + 1 + 1 = 5.6
However, in both cases total_distance = 1.2 mile and total_time = 3 min but the fares came out to be different.

If I understand correctly, this should work. If this isn't correct, please provide example inputs and outputs so I know when I have it right. The example code is in JavaScript.
interactive example
Constants:
var baseRate = 3.10;
var mileRate = 0.50;
var minuteRate = 0.50;
function fare(miles, minutes) {
var n = baseRate, mode;
Under a fifth of a mile, so base rate
if (miles <= 1/5) {
n = baseRate;
}
Per mile charge is added to the base rate. We subtract the 1/5 miles first.
else if (miles < minutes / 5) {
miles -= 1/5;
n += mileRate * miles;
}
We went less than a fifth of a mile per minute, so charge the per-minute rate.
else {
n += minutes * minuteRate;
}
return n;
}

If you are calculating the charge at the very end of the trip, then you just need to calculate the overall speed, and nominal time based on the break-even rule.
For one scenario, let's say the trip took 30 mins for 10 miles.
t = 30m
d = 10mi
s = 10/30 = 1/3 mi/m which is > (1/5 mi/m)
There are no delays so the the cost is based on miles.
cost = $3.10 + (10mi - 1/5mi) * $0.50 = $8.00
For another scenario, let's say the trip took 60 mins for 10 miles.
t = 60m
d = 10mi
s = 10/60 = 1/6 mi/m which is < (1/5 mi/m)
The nominal time for this trip is 50 minutes (10 / (1/5)), so there is a 10m delay, added to the charge.
cost = $3.10 + (10mi - 1/5mi) * $0.50 + (10m * $0.50) = $13

Related

Algorithmic approach to maximising a variable subject to some conditions (in a specific example)

I have a task allocation problem that I am finding difficult.
Suppose we have a group of individuals who each have different skills
Each group member can allocate 10 hours to each of Building and Crafting
A person's skill effects how well they can Build or Craft, i.e. a person with a Build skill of 0.5 can create 0.5 Build output with 1 hours' work
The group must satisfy the condition that Building output >= 10, and Crafting output >= 5
How can the group maximise “free time” (i.e. number of total hours spent unallocated) while still satisfying the minimum output conditions)?
Example:
Person Building Skill Crafting Skill
Alice 0.8 0.4
Bob 0.3 0.7
Cob 0.6 0.6
If each person had identical skills, no matter how the hours were allocated (as long as the conditions were satisfied) free time would have to be the same. But when each person has different skills, an “efficient” allocation of hours could vastly increase the amount of free time.
Would anyone know of any solutions that exist to this problem, and ones that work quickly even with a large amount of people and many more types of skills?
OR alternatively some a heuristical approach that can maximise free time to a decent enough extent (even if it's not perfect)
You can formulate problems like this as a linear program and then call out to a solver library to find the optimal solution.
Here's some sample Python.
from ortools.linear_solver import pywraplp
solver = pywraplp.Solver.CreateSolver("GLOP")
alice_build = solver.NumVar(0, 10, "alice_build")
alice_craft = solver.NumVar(0, 10, "alice_craft")
bob_build = solver.NumVar(0, 10, "bob_build")
bob_craft = solver.NumVar(0, 10, "bob_craft")
carol_build = solver.NumVar(0, 10, "carol_build")
carol_craft = solver.NumVar(0, 10, "carol_craft")
solver.Minimize(
alice_build + alice_craft + bob_build + bob_craft + carol_build + carol_craft
)
solver.Add(0.8 * alice_build + 0.3 * bob_build + 0.6 * carol_build >= 10)
solver.Add(0.4 * alice_craft + 0.7 * bob_craft + 0.6 * carol_craft >= 5)
# I'm not sure exactly what you meant by "Each group member can allocate 10
# hours to each of Building and Crafting". Delete these constraints if they can
# build for 10 hours and then craft for 10 hours.
solver.Add(alice_build + alice_craft <= 10)
solver.Add(bob_build + bob_craft <= 10)
solver.Add(carol_build + carol_craft <= 10)
solver.Solve()
print("alice_build", "=", alice_build.SolutionValue())
print("alice_craft", "=", alice_craft.SolutionValue())
print("bob_build", "=", bob_build.SolutionValue())
print("bob_craft", "=", bob_craft.SolutionValue())
print("carol_build", "=", carol_build.SolutionValue())
print("carol_craft", "=", carol_craft.SolutionValue())

Maximum profit that can be obtained - Buying and Selling

Say we have an accurate prediction of Messi’s prices for a period of N days. The prediction is given as a list in which p_i represents the player’s price in day i. Bob plans to make multiple, successive transactions during this period, but CAN’T have more than one Messi at a time, and therefore needs to sell him before buying him again.
Bob starts out with a limited budget B and can’t buy a Messi which costs more than he can afford. Of course, Bob can add to his budget any profit he gets from buying and selling his Messis. Luckily for him, some of the times he starts with a Messi from opening a random gift pack beforehand.
At the end Bob just wants to have as much profit as possible, and sell hist last Messi.
Input format :
On the first line of the input file, you will find 3 integers, N, B and M.
N represents the number of days for which Bob has a prediction of Messi’s price.
B represents Bob’s initial budget.
M can be either 0 or 1; 0 if Bob starts without an initial Messi to sell and 1 if he does start with an initial Messi to sell.
On the next line you will find N integers: p1, p2, … , pN, separated by a whitespace, in which pi, represents Messi’s price on day i.
Given testcases
Test 1
7 5 0
20 10 30 5 10 10 20
Correct answer : 15
Explanation : Bob starts with an initial budget of 5 and no initial Messi to sell. He cannot buy any Messi until his price drops to 5, so his profit is only (20-5) = 15
Test 2
7 0 1
20 10 50 80 60 20 10
Correct answer: 90
Explanation:
Bob starts with an initial budget of 0 and one Messi to sell. Therefore he sells his initial Messi for 20, buys him back for 10 and sells him for 80, so his profit is 20 + (80-10) = 90
This problem was given to me in an interview and I haven't been able to produce a functioning solution. In the meantime I've found a few simpler variations on this problem such as Maximum profit by buying and selling a share at most twice , but I've been unsuccessful in understanding how to adapt the thinking to my problem.
So far I've only been able to come up with a brute force solution that goes way beyond the time restrictions I was given (0.1 seconds for C++, where 1 <= N <= 10^5).
I'm looking for a solution and a way of thinking about this kind of problem, I can't seem to find the right way to think about this.
We can use dynamic programming.
Let's define f0(i) as the maximum budget we can obtain if we don't have Messi at the beginning of the day i.
Let f1(i) be the same value in case we've got him.
Base values for i = 0 depend on whether we have him at the very beginning or not.
The transitions go as follows:
We can go from i to i + 1 and do nothing
If we have Messi, we can sell him (setting f0(i + 1) = max(f0(i + 1), f1(i) + price(i)))
If we don't have him and our budget is big enough, we can buy him
(doing f1(i + 1) = max(f1(i + 1), f0(i) - price(i)))
The answer is f0(n) (which mean that all days passed and we don't have him).
This solution clearly requires a linear amount of time and space, so any
reasonable C++ implementation should fit your requirements.
First simplification of the problem is to convert the initial "gift" of Messi to an equal amount of money at the initial price of Messi. The user has a choice to either buy that Messi back or not at the beginning.
Afterwards, you would find the first price that's low enough for the user to buy a Messi, and discard every prediction before that. Then, find all the local minimal and local maximal of the predicted prices, and buy on all the minimals and sell on all the maximals, but remember not to buy back if the local minimal is the last prediction.
This should solve the problem in O(N).
EDIT: A local minimal or maximal can be found by the 2nd-degree difference of the sequence:
d[i] = p[i+1] - p[i]
d2[i] = d[i] - d[i-1]
If d2[i] > 0, then it's local minimal; if d2[i] < 0, then it's local maximal. Obviously there will be some boundary conditions that you need to take care of, but it shouldn't be too hard.
// input
long predictionLength;
long budget;
bool startWithMessi;
long prediction[MAX_PREDICTION_LENGTH];
// output
long profit;
ifstream fin;
fin.open( DATA_FILE_NAME );
fin >> predictionLength >> budget >> startWithMessi;
for( long day = 0; day < predictionLength; day++ )
fin >> prediction[day];
fin.close();
long money = budget;
bool messi = startWithMessi;
long dayIndex = 0;
while( dayIndex < predictionLength )
{
if( messi )
{
if( dayIndex == predictionLength - 1
|| prediction[dayIndex] > prediction[dayIndex + 1] )
{
money += prediction[dayIndex];
messi = false;
}
}
else
if( dayIndex < predictionLength - 1
&& prediction[dayIndex] < prediction[dayIndex + 1]
&& money >= prediction[dayIndex] )
{
money -= prediction[dayIndex];
messi = true;
}
dayIndex++;
}
profit = money - budget;
cout << profit << endl;

Finding an algorithm to a simulation

I have a single gold mine that produces gold at the rate of one gold unit every cycle of 20 hours (the 20 hours is not important). When it reaches 250 gold units, it immediately purchases another gold mine (costs 250 gold) so now it is producing two gold units every cycle.
Currently can only simulate it like this
int getCycles (int targetMines) {
int cycle = 0;
int goldMines = 1;
int balance = 0;
while (goldMines != targetMines) {
cycle++;
balance += goldMines;
if (balance / 250 >= 1) {
goldMines += balance / 250;
balance = balance % 250;
}
}
return cycle;
}
I am seeking a more elegant solution (perhaps more mathematic rather than computational?) to find the number of cycles (C) required to reach a target number of gold mines
It would be logarithmic. If every n cycles it doubles the gold mines, then to reach m gold mines you need n * log base 2 of m cycles. In this case they double every 250 cycles, so it would be 250 * log2 (m) cycles. In C that would be
numCycles = 250.0 * log2 (numMinesDesired);

Comparative rating algorithm

UseCase:
Assume that rating of object is from 1 to 5 stars.
It is already 50 votes with avarage rating 4.1.
When user make a vote(1-5stars), whe need to recalculate rating.
How to implement that logic? Problem is we don't know the value of every vote, only current rating and total votes.
newRating = (oldRating * oldCount + currentVote) / (oldCount + 1)
Well, basic arithmetic tells us that (50 * 4.1 + newvote) / 51 is the same as the average of all votes. You'll end up with roundoff errors if you do it repeatedly, and after a certain number of votes it's not even worth bothering with averaging in a single vote, but the basic formula is sound.
Assuming:
f = (1+2+3)/3 = 6/3 = 2
= (2+2+2)/3 = 6/3 = 2
We know that f=g. If we know the current rating is 2, and the total number of votes is 3, 2*3=6 as the sum of all votes. Let's add 4 to our average like so:
f = 6/3
f' = (6+4)/4 = 2.5

What's the best way to calculate remaining download time?

Let's say you want to calculate the remaining download time, and you have all the information needed, that is: File size, dl'ed size, size left, time elapsed, momentary dl speed, etc'.
How would you calculate the remaining dl time?
Ofcourse, the straightforward way would be either: size left/momentary dl speed, or: (time elapsed/dl'ed size)*size left.
Only that the first would be subject to deviations in the momentary speed, and the latter wouldn't adapt well to altering speeds.
Must be some smarter way to do that, right? Take a look at the pirated software and music you currently download with uTorrent. It's easy to notice that it does more than the simple calculation mentioned before. Actually, I notices that sometimes when the dl speed drops, the time remaining also drops for a couple of moments until it readjusts.
Well, as you said, using the absolutely current download speed isn't a great method, because it tends to fluctuate. However, something like an overall average isn't a great idea either, because there may be large fluctuations there as well.
Consider if I start downloading a file at the same time as 9 others. I'm only getting 10% of my normal speed, but halfway through the file, the other 9 finish. Now I'm downloading at 10x the speed I started at. My original 10% speed shouldn't be a factor in the "how much time is left?" calculation any more.
Personally, I'd probably take an average over the last 30 seconds or so, and use that. That should do calculations based on recent speed, without fluctuating wildly. 30 seconds may not be the right amount, it would take some experimentation to figure out a good amount.
Another option would be to set a sort of "fluctuation threshold", where you don't do any recalculation until the speed changes by more than that threshold. For example (random number, again, would require experimentation), you could set the threshold at 10%. Then, if you're downloading at 100kb/s, you don't recalculate the remaining time until the download speed changes to either below 90kb/s or 110kb/s. If one of those changes happens, the time is recalculated and a new threshold is set.
You could use an averaging algorithm where the old values decay linearly. If S_n is the speed at time n and A_{n-1} is the average at time n-1, then define your average speed as follows.
A_1 = S_1
A_2 = (S_1 + S_2)/2
A_n = S_n/(n-1) + A_{n-1}(1-1/(n-1))
In English, this means that the longer in the past a measurement occurred, the less it matters because its importance has decayed.
Compare this to the normal averaging algorithm:
A_n = S_n/n + A_{n-1}(1-1/n)
You could also have it geometrically decay, which would weight the most recent speeds very heavily:
A_n = S_n/2 + A_{n-1}/2
If the speeds are 4,3,5,6 then
A_4 = 4.5 (simple average)
A_4 = 4.75 (linear decay)
A_4 = 5.125 (geometric decay)
Example in PHP
Beware that $n+1 (not $n) is the number of current data points due to PHP's arrays being zero-indexed. To match the above example set n == $n+1 or n-1 == $n
<?php
$s = [4,3,5,6];
// average
$a = [];
for ($n = 0; $n < count($s); ++$n)
{
if ($n == 0)
$a[$n] = $s[$n];
else
{
// $n+1 = number of data points so far
$weight = 1/($n+1);
$a[$n] = $s[$n] * $weight + $a[$n-1] * (1 - $weight);
}
}
var_dump($a);
// linear decay
$a = [];
for ($n = 0; $n < count($s); ++$n)
{
if ($n == 0)
$a[$n] = $s[$n];
elseif ($n == 1)
$a[$n] = ($s[$n] + $s[$n-1]) / 2;
else
{
// $n = number of data points so far - 1
$weight = 1/($n);
$a[$n] = $s[$n] * $weight + $a[$n-1] * (1 - $weight);
}
}
var_dump($a);
// geometric decay
$a = [];
for ($n = 0; $n < count($s); ++$n)
{
if ($n == 0)
$a[$n] = $s[$n];
else
{
$weight = 1/2;
$a[$n] = $s[$n] * $weight + $a[$n-1] * (1 - $weight);
}
}
var_dump($a);
Output
array (size=4)
0 => int 4
1 => float 3.5
2 => float 4
3 => float 4.5
array (size=4)
0 => int 4
1 => float 3.5
2 => float 4.25
3 => float 4.8333333333333
array (size=4)
0 => int 4
1 => float 3.5
2 => float 4.25
3 => float 5.125
The obvious way would be something in between, you need a 'moving average' of the download speed.
I think it's just an averaging algorithm. It averages the rate over a few seconds.
What you could do also is keep track of your average speed and show a calculation of that as well.
For anyone interested, I wrote an open-source library in C# called Progression that has a "moving-average" implementation: ETACalculator.cs.
The Progression library defines an easy-to-use structure for reporting several types of progress. It also easily handles nested progress for very smooth progress reporting.
EDIT: Here's what I finally suggest, I tried it and it provides quite satisfying results:
I have a zero initialized array for each download speed between 0 - 500 kB/s (could be higher if you expect such speeds) in 1 kB/s steps.
I sample the download speed momentarily (every second is a good interval), and increment the coresponding array item by one.
Now I know how many seconds I have spent downloading the file at each speed. The sum of all these values is the elapsed time (in seconds). The sum of these values multiplied by the corresponding speed is the size downloaded so far.
If I take the ratio between each value in the array and the elapsed time, assuming the speed variation pattern stabalizes, I can form a formula to predict the time each size will take. This size in this case, is the size remaining. That's what I do:
I take the sum of each array item value multiplied by the corresponding speed (the index) and divided by the elapsed time. Then I divide the size left by this value, and that's the time left.
Takes a few seconds to stabalize, and then works preety damn well.
Note that this is a "complicated" average, so the method of discarding older values (moving average) might improve it even further.

Resources