Optimizing allocation algorithm needed - algorithm

Today I encountered an interesting problem when accounting for the travel costs of my last journey with my friends.
Let's assume we had the following expenditures:
# expenditures in US-$
Peter= 117
Joe= 38
Bill= 15
Chris= 0
Alan= 209
Tim= 201
Ahmet= 124
Pati= 57
Steven= 74
Now we have decided that everybody should pay the same amount of money. Given that the average expenditure was 92.77778 US-$, The Balances look like this:
# balances in US-$
Peter= 24.22
Joe= -54.78
Bill= -77.78
Chris= -92.78
Alan= 116.22
Tim= 108.22
Ahmet= 31.22
Pati= -35.78
Steven=-18.78
So now I would like to find an optimization method where we have a minimum number of total bank-transactions and a fairly distributed share of transactions over all participants (so two optimization aims)
I have looked up the Stable Marriage Problem but I think it doesn't apply in this case.

This doesn't seem like a difficult problem -- sort the participants by ascending expenditures, then, in that order, have each participant transfer their negated (current) balance to the next participant. n-1 transactions, and at most one transaction per participant. Each of which, of course, is the best you can do in general.
Or is there some extra constraint I'm missing?

This method only solves the part of "minimum number of total bank-transactions".
People are grouped into two categories, say Giver (whose balance is negative) and Receiver(whose balance is positive).
Key Observation In an optimum solution, a giver should always give away money, a receiver should always receive money. It's impossible for person A gives money to B and then B gives some money to C.
Now comes the solution.
While (there is some giver or receiver) {
Find the giver with the largest balance, say A.
Find the receiver with the largest balance, say B.
Let A gives as much money as B needs.
Delete Person if his/her balance becomes 0.
}

Related

How to Schedule Tasks

There is a carwash that can only service 1 customer at a time. The goal of the car wash is to have as many happy customers as possible by making them wait the least amount of time in the queue. If the customers can be serviced under 15 minutes they are joyful, under an hour they are happy, between 1 hour to 3 hours neutral and 3 hours to 8 hours angry. (The goal is to minimize angry people and maximize happy people). The only caveat to this problem is that each car takes a different amount of time to wash and service so we cannot always serve on first come first serve basis given the goal we have to maximize customer utility. So it may look like this:
Customer Line :
Customer1) Task:6 Minutes (1st arrival)
Customer2) Task:3 Minutes (2nd arrival)
Customer3) Task:9 Minutes (3rd)
Customer4) Task:4 Minutes (4th)
Service Line:
Serve Customer 2, Serve Customer 1, Serve Customer 4, Serve Customer 3.
In this way, no one waited in line for more than 15 minutes before being served. I know I should use some form of priority queue to implement this but I honestly know how should I give priority to different customers. I cannot give priority to customers with the least amount of work needed since they may be the last customer to have arrived for example (others would be very angry) and I cannot just compare based on time since the first guy might have a task that takes the whole day.So how would I compare these customers to each other with the goal of maximizing happiness?
Cheers
This is similar to ordering calls to a call center. It becomes more interesting when you have gold and silver customers. Anyway:
Every car has readyTime (the earliest time it can be washed, so it's arrival time - which might be different for each car) and a dueTime (the moment the customer becomes angry, so 3 hours after readyTime).
Then use a constraint solver (like OptaPlanner) to determine the order of the cars (*). The order of the cars (which is a genuine planning variable) implies the startWashingTime of each car (which is a shadow variable), because in your example, if customer 1 is ordered after customer 2 and if we start at 08:00, we can deduce that customer 1's startWashingTime is 08:03.
Then the endWashingTime is startWashingTime + washingDuration.
Then it's just a matter of adding 2 constraints and let the solver solve() it:
endWashingTime must be lower than dueTime, this is a hard constraint. This is to have no angry customers.
endWashingTime must be lower than startTime plus 15 minutes, this is a soft constraint. This is to maximize happy customers.
(*) This problem is NP-complete or NP-hard because you can relax it to a knapsack problem. In practice this means: you can't write an algorithm for it that scales out and finds the optimal solution in reasonable time. But a constraint solver can get you close.

Even prize distribution

I'm currently facing interesting algorithm problem and I am looking for ideas or possible solutions. Topic seems to be common so maybe it's known and solved but I'm unable to find it.
So lets assume that I'm running shop and
I'm making lottery for buying customers. Each time they buy something they can win prize.
Prizes are given to customers instantly after buying.
I have X prizes and
I will be running lottery for Y days
Paying customer (act of buying, transaction) should have equal chance to win prize
Prizes should be distributed till last day (at last day there should be left some prizes to distribute)
There can not be left prizes at the end
I do not have historical data of transactions per day (no data from before lottery) to estimate average number of transactions (yet lottery could change number of transactions)
I can gather data while lottery is running
It this is not-solvable, what is closest solution?
Instant prize distribution have to stay.
Possible Solution #1
Based on #m69 comment
Lets says there are 6 prizes (total prizes) and 2 days of lottery.
Lets define Prizes By Day as PBD (to satisfy requirement have prizes till last day).
PBD = total prizes / days
We randomly choose as many as PBD events every day. Every transaction after this event is winning transaction.
Can be optimized to no to use last hour of last day of lottery to guarantee giving away all of prizes.
Pluses
Random. Simple, elegant solution.
Minuses
Seems that users have no equal chance to win.
Possible Solution #2
Based on #Sorin answer
We start to analyze first time frame (example 1 hour). And we calculate chance to win as:
where:
Δprizes = left prizes,
Δframes = left frames
What you're trying to do is impossible. Once you've gave away the last prize you can't prove any guarantee for the number of customers left, so not all customers will have equal chance to win a prize.
You can do something that approximates it fairly well. You can try to estimate the number of customers you will have, assume that they are evenly distributed and then spread the prizes over the period while the contest is running. This will give you a ratio that you can use to say if a given customer is a winner. Then as the contest progresses, change the estimates to match what you see, and what prizes are left. Run this update every x (hours/ minutes or even customer transaction) to make sure the rate isn't too low and every q prizes to make sure the rate isn't too high. Don't run the update too often if the prizes are given away or the algorithm might react too strongly if there's a period with low traffic (say overnight).
Let me give you an example. Say you figure out that you're going to see 100 customers per hour and you should give prizes every 200 customers. So roughly 1 every 2 hours. After 3 hours you come back and you see you saw 300 customers per hour and you've given out 4 prizes already. So you can now adjust the expectation to 300 customers per hour and adjust the distribution rate to match what is left.
This will work even if your initial is too low or too high.
This will break badly if your estimate is too far AND you updates are far in between (say you only check after a day but you've already given away all the prizes).
This can leave prizes on the table. If you don't want that you can reduce the amount of time the program considers the contest as running so that it should finish the prizes before the end of the contest. You can limit the number of prizes awarded in a given day to make the distribution more uniform (don't set it to X/Y, but something like X/Y * .25 so that there's some variation), and update the limit at the end of the day to account for variation in awards given.

A fast algorithm for determining timeshare requests

I am writing a program that will simulate how members of a certain timeshare will request their apartments. The apartments are only available for certain 'events' throughout the year, and the events each have different durations (counted in days). For each event, there are a number of apartments available, which are divided into groups according to cost (points per day).
We may also have the situation that some of the apartments are already rented out, so it is possible that certain events cannot admit a certain apartment type.
Now I want a member to request apartments according to this strategy:
Maximizing the number of total event days is first priority.
Maximizing the number of points spent is second priority (so the user requests the best possible apartment that he/she can afford and still have as many days as possible).
The total cost of the requested apartments cannot exceed the total amount of available points for that user.
Obviously, if there are no more apartments of a given type for a certain event, the user should not request that particular apartment/event combo.
I am wondering whether the problem is similar to the problem described here:
http://en.wikipedia.org/wiki/Hungarian_algorithm
in that it (I suppose) possible to frame this as a matrix problem where each entry has a cost associated with it.
However, the difference is that for my problem, I am allowed to use the same apartment for several events - it's not 'spent' once it has been used for one event. Also, the cost per entry is not really one-dimensional, since each event/apartment combo both has a number of days associated with it and a number of points - both of which should be maximized (but with priority given to the number of days).
As an example, let's say there are three apartment types, costing 75, 100, and 125 points per day, and three events, with a duration of 2, 10, and 4 days. Let's further say many of the apartments are taken, so the availability matrix looks like this:
cost
75 100 125
2 True False True
days 10 False False True
4 True False True
Let's also say the user has 1250 points available. The solution, in this case, would be that the user requests the 10-day event with the 125-point apartment and nothing else.
The brute-force way of doing this would perhaps be a recursive algorithm:
Let n be the number of events you are currently trying
Find all combinations of events and apartments, and calculate the combo that maximizes the number of days, then the number of points spent (this will both include all permutations of n events, but also the number of ways 3 apartment types can be assigned to n events).
Let n=n-1
This will quickly become overwhelming when the number of events goes up, I think, so I am wondering whether there are any algorithms that can solve this in a less expensive way?
If you have access to a library for http://en.wikipedia.org/wiki/Integer_programming you could try throwing this at it.
Even if you have only one choice of cost for each event, so that you are just trying to chose combinations of events that cover as many total days as possible without going over budget, I think this reduces to http://en.wikipedia.org/wiki/Knapsack_problem. This means that it is unlikely to be solved exactly by a worst case polynomial time algorithm such as the Hungarian algorithm.

Finding most distinct elements in a set

Say we have a perfume shop that has 100 different perfumes.
Let's say 10,000 customers come in an rate each perfume one through five stars.
Let's say the question is: "how to best construct a pack of 5 perfumes so that 95% customers will give a 4+ star rating for at least one of them"
How to do this algorithmically?
NOTE: I can see that even the question isn't properly formed; there's no guarantee that such a construction even exists. There is a trade-off between 2 parameters.
NOTE: Also, (and this makes the perfume analogy becomes slightly artificial), it doesn't matter whether we get one good match or three good matches. So {4.3, 0, 0, 0, 0} would be equivalent to {4.3, 4.2, 4.2, 4.2, 4.2} -- in both cases the score is 4.3.
Let's say for the purpose of argument that perfumes 0-19 are sweet, perfumes 20-39 are sour, etc (sim. salt, bitter, unami)
So there would be very high crosscorrelation between 0-19.
If you modelled this with 100 points in space, then 0-19 would all attract each other very strongly, they would form a cluster.
Similarly you would get 4 other clusters for the other four tastes.
So from just one metric, we have separated out 5 distinct flavours.
But does this technique extend?
π
PS just giving the names of related techniques would be very helpful, as this would allow me to Google for further information. So any answer that just restates the question in industry accepted terminology would be useful!
This algorithm should find a solution to the problem:
Order the perfumes by the number of customers giving a 4+ rating
Choose the first perfume not concidered yet from the list
Delete the ratings from the customers now satisfied.
Repeat the process for perfumes 2 - 5 in the pack.
Backtrace when neccessary to obtain a selection satisfying the criterion.
The true problem is NP-hard, but you can make use of a greedy algorithm:
Let C be the whole of your customers.
Assign to each perfume a coverage given by the number of customers in C that gave 4+ to each perfume
Sort by descending coverage. If C is empty and all coverages are zero, choose a perfume at random (actually, if C is nonzero but < 5% of the original, your requisite is met)
Remove from C all customers (not ratings) satisfied by the perfume just chosen
Repeat from 2 unless you already have 5 perfumes.
This automatically takes care of taste clustering: a customer giving high marks to sweet perfumes will be satisfied by the most voted sweet perfume, and he will then be struck out from C, all his further ratings ignored, and the algorithm will proceed to satisfy other customers.
Also, you should notice that even if you can't satisfy the requisite (95%, 4+) with five perfumes, perfume similarity will ensure that this algorithm maximizes both the coverage and the marks - so you might end up with, say, (93%, 3.9).
Also, suppose that 10% of users do not give any marks above 3. There's no way that you can 4-satisfy 95% of customers, since 10% of total are at most 3-satisfiable. You might want to build C with customers that actually did give at least one 4+ rating.
Or you could change the algorithm and instead of the one in your question, decide on using a knapsack: you want to take home the highest cumulative rating. This also raises the likelihood of a customer being satisfied by the overall package (as is, he is almost guaranteed to very much like one perfume, but he might strongly dislike the other four).

Algorithm needed - benelux contest 2007

This question (last one) appeared in Benelux Algorithm Programming Contest-2007
http://www.cs.duke.edu/courses/cps149s/spring08/problems/bapc07/allprobs.pdf
Problem Statement in short:
A Company needs to figure out strategy when to - buy OR sell OR no-op on a given input so as to maximise profit. Input is in the form:
6
4 4 2
2 9 3
....
....
It means input is given for 6 days.
Day 1: You get 4 shares, each with price 4$ and at-max you can sell 2 of them
Day 2: You get 2 shares, each with price 9$ and at-max you can sell 3 of them
.
We need to output the maximum profit which can be achieved.
I m thinking about how to go for this problem. It seems to me that if we apply brute force, it will take too much time. If this can be converted to some DP problem like 0-1 Knapsack? Some help will be highly appreciated.
it can be solved by DP
suppose there are n days, and the total number of stock shares is m
let f[i][j] means, at the ith day, with j shares remaining, the maximum profit is f[i][j]
obviously, f[i][j]=maximum(f[i-1][j+k]+k*price_per_day[i]), 0<=k<=maximum_shares_sell_per_day[i]
it can be further optimized that, since f[i][...] only depends on f[i-1][...], a rolling array can be used here. hence u need only to define f[2][m] to save space.
total time complexity is O(n*m*maximum_shares_sell_per_day).
perhaps it can be further optimized to save time. any feedback is welcome
Your description does not quite match the last problem in the PDF - in the PDF you receive the number of shares specified in the first column (or are forced to buy them - since there is no decision to make it does not matter) and can only decide on how many shares to sell. Since it does not say otherwise I presume that short selling is not allowed (else ignore everything except the price and go make so much money on the derivatives market that you afford to both bribe the SEC or congress and retire :-)).
This looks like a dynamic program, where the state at each point in time is the total number of shares you have in hand. So at time n you have an array with one element for each possible number of shares you might have ended up with at that time, and in that element you have the maximum amount of money you can make up to then while ending up with that number of shares. From this you can work out the same information for time n+1. When you reach the end, then all your shares are worthless so the best answer is the one associated with the maximum amount of money.
We can't do better than selling the maximum amount of shares we can on the day with the highest price, so I was thinking: (this may be somewhat difficult to implement (efficiently))
It may be a good idea to calculate the total number of shares received so far for each day to improve the efficiency of the algorithm.
Process the days in decreasing order of price.
For a day, sell amount = min(daily sell limit, shares available) (for the max price day (the first processed day), shares available = shares received to date).
For all subsequent days, shares available -= sell amount. For preceding days, we binary search for (shares available - shares sold) and all entries between that and the day just processed = 0.
We might not need to physically set the values (at least not at every step), just calculate them on-the-fly from the history thus-far (I'm thinking interval tree or something similar).

Resources