Find maximum point out of n tasks - algorithm

Exact problem statement :
Given N tasks, find the maximal points that can be achieved by finishing them
Problem Constraints:
There are T minutes for completing N tasks
Solutions can be submitted at any time, including exactly T minutes after the start
i-th task submitted t minutes after the start, will get
maxPoints[i] - t * pointsPerMinute[i] points
i-th task takes requiredTime[i] minutes to solve
Input Format
Line 1: T, total minutes available to finish
Line 2: Comma separated list of maxPoints
Line 3: Comma separated list of pointsPerMinute
Line 4: Comma separated list of requiredTime
Sample Input
75
250 500 1000
2 4 8
25 25 25
Sample Output
1200
Explanation
First, solve the third task 25 minutes after the start of the contest. Get 1000 - 8 * 25 = 800 points
Second, solve the second task 50 minutes after the start of the contest. Get 500 - 4 * 50 = 300 points
Third, solve the first task 75 minutes after the start of the contest. Get 250 - 2 * 75 = 100 points
In total, get 800 + 300 + 100 = 1200 points
I was able to get the solution by permuting and the calculating the point for each arrangement. I couldn't figure out optimized solution for this.

I use greedy algorithm to solve this.
I use m for maxPoint, p for pointsPerMinute, r for requiredTime.
Consider finishing A task before B task, you can get:
Point(A, B) = m[A] - p[A] * r[A] + m[B] - p[B] * (r[A] + r[B])
Finishing B task before A task, you can get:
Point(B, A) = m[B] - p[B] * r[B] + m[A] - p[A] * (r[A] + r[B])
If you should finish A task before B task, Point(A, B) need greater than Point(B, A), so Point(A, B) - Point(B, A) >= 0.
For some calculation, we can get:
r[A] / p[A] < r[B] / p[B].
That means, if we need to finish A task before B task, r[A] / p[A] should less than r[B] / p[B]. And we can sort all tasks by this and count the answer.

Related

How to devide some fixed amount of reward points to players of a racing game in a fair way depending on their finishing time

I'm in need of some kind of algorithm I can't figure out on my own sadly.
My biggest problem is that I have no good way to describe the problem... :/
I will try like this:
Imagine you have a racing game where everyone can try to be the fastest on a track or map. Every Map is worth 100 Points in total. If someone finished a map in some amount of time he gets a record in a database. If the player is the first and only player to finish this map he earns all the 100 points of this map.
Now, that's easy ;) but...
Now another player finishes the map. Let's imagine the first player finishes in 50 Seconds and the 2nd player finishes in 55 seconds, so a bit slower. I now need a calculation depending on both records in the database. Each of both players now earn a part of the 100 points. The faster player a bit more then the slower player. Let's say they finished the exact same time they both would get 50 points from 100, but as the first one is slightly faster, he now earns something around 53 of the points and the slower player just 47.
I started to calculate this like this:
Sum of both records is 105 seconds, the faster player took 50/105 in percent of this, so he earns 100-(50/105*100) points and the slower player 100-(55/105*100) points. The key to this is, that all points distributed among the players always equals to 100 in total. This works for 2 players, but it breaks at 3 and more.
For example:
Player 1 : 20 seconds
Player 2 : 20 seconds
Player 3 : 25 seconds
Calculation would be:
Player 1: 100-(20/65*100) = 69 points
Player 2: 100-(20/65*100) = 69 points
Player 3: 100-(25/65*100) = 61 points
This would no longer add up to 100 points in total.
Fair would be something around values of:
Player 1 & 2 (same time) = 35 points
Player 3 = 30 points
My problem is i can't figure out a algorithm which solves this.
And I need the same algorithm for any amount of players. Can someone help with an idea? I don't need a complete finished algorithm, maybe just an idea at which step i used the wrong idea, maybe the sum of all times is already a bad start.
Thx in advance :)
We can give each player points proportional to the reciprocal of their time.
One player with t seconds gets 100 × (1/t) / (1/t) = 100 points.
Of the two players, the one with 50 seconds gets 100 × (1/50) / (1/50 + 1/55) ≈ 52.4, and the one with 55 gets 100 × (1/55) / (1/50 + 1/55) ≈ 47.6.
Of the three players, the ones with 20 seconds get 100 × (1/20) / (1/20 + 1/20 + 1/25) ≈ 35.7, and the one with 25 seconds gets 100 × (1/25) / (1/20 + 1/20 + 1/25) ≈ 28.6.
Simple observation: Let the sum of times for all players be S. A person with lower time t would have a higher value of S-t. So you can reward points proportional to S-t for each player.
Formula:
Let the scores for N players be a,b,c...,m,n. Total sum S = a+b+c...+m+n. Then score for a given player would be
score = [S-(player's score)]/[(N-1)*S] * 100
You can easily see that using this formula, the sum of scores of all players will be always be 100.
Example 1:
S = 50 + 55 = 105, N-1 = 2-1 = 1
Player 1 : 50 seconds => score = ((105-50)/[1*105])*100 = 52.38
Player 2 : 55 seconds => score = ((105-55)/[1*105])*100 = 47.62
Similarly, for your second example,
S = 20 + 20 + 25 = 65
N - 1 = 3 - 1 = 2
For Player 1, (S-t) = 65-20 = 45
Player 1's score => (45/(2*65))*100 = 34.6
Player 2 => same as Player 1
For Player 3, (S-t) = 65-25 = 40
Player 3's score => (40/(2*65))*100 = 30.8
This method avoids any division in the intermediate states, so there will be no floating point issues for the calculations.

How to calculate one certain value from a rolling-window estimation in Stata

I'm using Stata to estimate Value-at-risk (VaR) with the historical simulation method. Basically, I will create a rolling window with 100 observations, to estimate VaR for the next 250 days (repeat 250 times). Hence, as I've known, the rolling window with time series command in Stata would be useful in this case. Here is the process:
Input: 350 values
1. Ascending sort the very first 100 values (by magnitude).
2. Then I need to take the 5th smallest for each window.
3. Repeat 250 times.
Output: a list of the 5th values (250 in total).
Sound simple, but I cannot do it the right way. This was my attempt below:
program his,rclass
sort lnreturn
return scalar actual=lnreturn in 5
end
tsset stt
time variable: stt, 1 to 350
delta: 1 unit
rolling actual=r(actual), window(100) saving(C:\result100.dta, replace) : his
(running his on estimation sample)
And the result is:
Start end actual
1 100 -.047856
2 101 -.047856
3 102 -.047856
4 103 -.047856
.... ..... ......
251 350 -.047856
What I want is 250 different 5th values in panel "actual", not the same like that.
If I understand this correctly, you want the 5th percentile of values in a window of 100. That should yield to summarize, detail or centile. I see no need to write a program.
Your bug is that your program his calculates the same thing each time it is called. There is no communication about windows other than what is explicit in your code. It is like saying
move here: now add 2 + 2
move there: now add 2 + 2
move to New York: now add 2 + 2
The result is invariant to your supposed position.
Note that I doubt that
return scalar actual=lnreturn in 5
really is your code. lnreturn[5] should work.
UPDATE You don't even need rolling here. Looping over data is easy enough. The data in this example are clearly fake.
clear
* sandpit
set obs 500
set seed 2803
gen y = ceil(exp(rnormal(3,2)))
l y in 1/5
* initialise
gen p5 = .
* windows of length 100: 1..100, 101..200, ...
quietly forval j = 1/401 {
local J = `j' + 99
su y in `j'/`J', detail
replace p5 = r(p5) in `j'
}
* check first calculation
su y in 1/100, detail
l in 1/5

Algorithm to find the 'possible' combinations of variables with constraints in Matlab?

Say I have 7 items in A and 4 items in B
A=[10;40;90;130;200;260;320]
B=[100;300;500;1000]
I want to have the list of possible combinations where :
All sub-components of A MUST be included
sub-components of B can be added until the the SUM of all sub-componenets added is greater than 2000
Anyone has an idea how to do this in Matlab ?
My try :
X=sum(A);
y=1;
for Y=1:((length(A))-1);
X=X+B(y);
if(X>2000)
disp('Following is unacceptable')
end
y=y+1
end
However this code is not correct. It just adding the first element of B then adding it with the second element and so on. It isn't providing me with possible combinations.
Example :
sum(A) + B(1) = OK
sum(A) + B(4) = NOT OK
sum(A) + B(1) + B(2) = OK
sum(A) + B(2) + B(3) = OK
etc...
I want this to be automated if values of A or B change in the future. I am not sure if this is a case of probability as well.
Just use nchoosek and a double for-loop to go through all possible combinations of elements in B:
SA = sum(A);
for k = 1:numel(B)
for idx = nchoosek(1:numel(B), k)'
B_subset = B(idx);
if (SA + sum(B_subset) <= 2000)
disp([A(:)', B_subset(:)'])
end
end
end
This prints all combinations with a sum less than (or equal to) 2000. For your example we get:
10 40 90 130 200 260 320 100
10 40 90 130 200 260 320 300
10 40 90 130 200 260 320 500
10 40 90 130 200 260 320 100 300
10 40 90 130 200 260 320 100 500
10 40 90 130 200 260 320 300 500
10 40 90 130 200 260 320 100 300 500
Explanation:
The inner for-loop:
The inner for-loop uses nchoosek(1:numel(B), k), which generates all k-length combinations out of 1...length(B) (I'm using numel instead of length out of habit; in this case it has the same effect). For example, in our case B has 4 elements, so for k = 3 we get nchoosek(1:4, 3):
1 2 3
1 2 4
1 3 4
2 3 4
What we get from this is all the possible k-length combinations of indices of elements in B. In each iteration, this for-loop assigns a different combination of indices to idx. How do we convert the indices of B to real elements? We simply write B(idx).
Inside loop the combination is tested: if the total sum(A) + sum(B(idx)) is less than (or equal to) 2000, that combination is displayed.
The outer for-loop:
The outer for-loop simply iterates over all possible lengths of combinations (that is, over all possible values of k).
Hope that helps!
P.S:
Some MATLAB programming tips for the future:
1. Variable names are case-sensitive.
2. You don't need to increment the loop variable. The for loop does that automatically for you.
The best approach would involve some recursion, like this:
sumA=sum(A);
find_CombinationsOfB(B,sumA,[])
function ret=findCombinationsOfB(in_vals,total_sum,already_contained)
if total_sum>2000
ret=false;
else
for y=1:length(in_vals);
if (~findCombinationsOfB(in_vals([1:(y-1);(y+1):length(in_vals)],total_sum+in_vals(y),[already_contained in_vals(y))
display([already_contained in_vals])
end
end
ret=true;
end
Essentially what this does is tries each combination of B. It will print any that don't add up to 2000, including the sum from A.
Step by step, here's what it does:
Initially, the full array of B is passed, along with the sum of A. An empty array is passed to store which elements of B have been used so far.
Each element added in turn to the function, and called again with a new sum, and with a value missing from the array.
If at any point the array sum is over 2000, it stops that chain of reasoning.
If you want to know more about how this works, print in_vals, total_sum, and already_contained in the start of the function, like this:
fprintf("in_vals=%s total_sum=%i already_contained=%s",mat2str(in_vals),total_sum,mat2str(already_contained));
It should show you at each iteration what is happening.
Assuming B is not very long (around 10 elements), an exhaustive search through all combinations will work just fine. You can carry out this exhaustive search with a recursive function, but the code below uses a trick that's particularly concise in MATLAB: it sweeps through all combinations of the elements of B by representing each combination as a binary bit string.
% examine each of 2^length(B) combinations
for i=0:2^length(B)-1
% converts the binary string into an array of 0 and 1 used to select elements in B
combo = dec2bin(i, length(B))-'0';
% print the combination of elements if their sum is large
if combo * B + sum(A) > 2000
disp(find(combo));
end
end
There are 2^length(B) possible combinations. This examines them in turn, representing the combination as a binary string of length length(B), and evaluating the sum of these elements (with a dot product between the bit string and B).

Scheduling: advance deadline for implicit-deadline rate monotonic algorithm

Given a set of tasks:
T1(20,100) T2(30,250) T3(100,400) (execution time, deadline=peroid)
Now I want to constrict the deadlines as Di = f * Pi where Di is new deadline for ith task, Pi is the original period for ith task and f is the factor I want to figure out. What is the smallest value of f that the tasks will continue to meet their deadlines using rate monotonic scheduler?
This schema will repeat (synchronize) every 2000 time units. During this period
T1 must run 20 times, requiring 400 time units.
T2 must run 8 times, requiring 240 time units.
T3 must run 5 times, requiring 500 time units.
Total is 1140 time units per 2000 time unit interval.
f = 1140 / 2000 = 0.57
This assumes long-running tasks can be interrupted and resumed, to allow shorter-running tasks to run in between. Otherwise there will be no way for T1 to meet it's deadline once T3 has started.
The updated deadlines are:
T1(20,57)
T2(30,142.5)
T3(100,228)
These will repeat every 1851930 time units, and require the same time to complete.
A small simplification: When calculating factor, the period-time cancels out. This means you don't really need to calculate the period to get the factor:
Period = 2000
Required time = (Period / 100) * 20 + (Period / 250) * 30 + (Period / 400) * 100
f = Required time / Period = 20 / 100 + 30 / 250 + 100 / 400 = 0.57
f = Sum(Duration[i] / Period[i])
To calculate the period, you could do this:
Period(T1,T2) = lcm(100, 250) = 500
Period(T1,T2,T3) = lcm(500, 400) = 2000
where lcm(x,y) is the Least Common Multiple.

Shortest path algorithm for an analog clock

I've got a c homework problem that is doing my head in and will be greatful if anyone can help point me in the right direction.
If I have two minutes points on an analog watch such as t1 (55 minutes) and t2 (7 minutes), I need to calculate the shortest amount of steps between the two points.
What I've come up with so far is these two equations:
-t1 + t2 + 60 =
-55 + 7 + 60
= 12
t1 - t2 + 60 =
55 - 7 + 60
= 108
12 is lower then 108, therefore 12 steps is the shortest distance.
This appears to work fine if I compare the two results and use the lowest. However, if I pick out another two points for example let t1 = 39 and t2 = 34 and plug them into the equation:
-t1 + t2 + 60 = -39 + 34 + 60 = 55
t1 - t2 + 60 = 39 - 34 + 60 = 35
35 is lower then 55, therefore 35 steps is the shortest distance.
However, 35 isn't the correct answer. 5 steps is the shorest distance (39 - 34 = 5).
My brain is a little fried, and I know I am missing something simple. Can anyone help?
What you want is addition and subtraction modulo 60. Check out the % operator. Make sure you handle negatives correctly.
If you don't want to use % operator, try to think this way:
for each couple of points (t1; t2), you'll have two way to connect them: one path will cross 0 (12 o'clock), and the other won't.
Provided that t2 >= t1, the second distance is easy to calculate: it's t2 - t1.
the other distance is t1 + 60 - t2
I think your mistake was adding 60 in the first expression.

Resources