How to find the cheapest combo of metro subscription - algorithm

Lets say we have the following fares available :
1 trip
2 trips
10 trips
unlimited weekend (saturday to sunday, not 2 days)
1 day
3 days
unlimited week (monday to sunday, not 7 days)
unlimited month (1st to last day of month)
... with a price for every one of them.
The problem is : **How to determine what set of subscriptions to chose given a date of arrival and a date of departure ? **
Lets say we want the solution for n between 1 and 8, n being the number of time we take the metro daily (so we assume we take the metro the same number of time every day)
For example it would say something like :
n = 1
Arriving on Friday 19th and leaving Thursday 23th, the best is taking the 1 trip, then the weekend, then the 2 trips (didnt calculate but you see the point)
n = 2
...
I have found examples with only 1 day, 2 days, 7 days fares with dynamic programming, but it looks a lot harder when you considerate the days of the week.
Thanks :)

I like to view this kind of dynamic program as finding a shortest path in a directed acyclic graph.
Each node of the graph encodes
what the current day is (either during the travel period or the day after), and
how many trips remain on trip-limited passes (at most n + 9).
Each arc represents either
purchasing a specific pass at a specific time (the length of the arc is the cost of this pass), or
using trip-limited passes to cover the day's trips (the length of the arc is zero).
The time-limited passes advance the day to the first day they no longer work. The trip-limited passes increase the number of remaining trips. The zero-cost arcs advance the day by one while decreasing the number of remaining trips by n.
Given the shortest path, it is easy to decode it to a plan for purchasing passes.
(P.S. I don't know what the rules are on, e.g., purchasing a week pass on a Tuesday for the rest of the week. Even if this is not allowed, you're going to want to put arcs for the time-limited passes that could have been purchased on a previous day during the travel period.)

Related

Dynamic Programming - Break Scheduling Problem With Decreasing Work Capacity

Assume you are given t1, t2, t3, ..., tn amount of tasks to finish every day. And once you start working, you can only finish c1, c2, c3, ..., cn tasks until spending 1 day resting. You can spend multiple days resting too. But you can only do the tasks which are given you that day. For example;
T[] = {10, 1, 4, 8} given tasks;
C[] = {8, 4, 2, 1} is the capacity of doing tasks for each day.
For this example, optimal solution is giving a break on the 3rd day. That way you can complete 17 tasks in 4 days:
1st day 8 (maximum 10 tasks, but c1=8)
2nd day 1 (maximum 1 task, c2=4)
3rd day 0 (rest to reset to c1)
4th day 8 (maximum 8 tasks, c1=8)
Any other schedule would result with fewer tasks getting done.
I'm trying to find the recurrence relation for this dynamic programming problem. Can anyone help me? I find this question but mine is different because of the decreasing work capacity and there are different number of jobs each day. Reference
If I got you right you have an amount of tasks to do, t(i) for every day i. Also you have some kind of a given internal restriction sequence c(j) for a current treak day j where j can be reseted to 0 if no task was done that day. Goal is to maximizie the solved tasks.
Naive approach is to store for each day i a list for every state j how many tasks were done. Fill the data for the first day. Then for every following day fill the values for the "no break" case - which is
value(i-1,j-1)+min(t(i),c(j)). Choose the maximum from the previous day to fill the "break" entry. Repeat until last day. Choose the highest value and trace back the path.
Example for above
Memory consumtption is pretty easy: O(number of days * number of states).
If you are only interested in the value and not the schedule the memory consumption would be the O(number of states).
Time consumption is a bit more complex, so lets write some pseudo code:
For each day i
For each possible state j
add and write values
choose maximum from previous day for break state
choose maximum
For each day
trace back path
The choose maximum-function would have a complexity of O(number of states).
This pseudo code results in time consumption O(number of days * number of states) as well.

Algorithm for heavily restricted Knapsack problem

I have a following problem to solve:
We have 53 weeks in a year, for each week we need to choose one model from the list: [A1, A2,....,F149, F150]. In total around 750 models in 6 classes: A,B,C,D,E,F.
Models can repeat and each has a specific value from around 3 to 10 and a weight. The goal is to achieve a target total value of 280+-5% with a minimal weight by the end of the year.
However there are a ton of restrictions. For example:
Models must be held for at least 4 weeks in a row. If we have chosen A1 for week 1, then we need to choose A1 for weeks 2,3,4;
If we have chosen model classes E,F then, after they end, we cannot choose E, F for another 4 weeks.
Throughout the year we can only choose 23 models of class D.
an so on
What I've tried so far:
Based on a target value create a corridor of allowed values throughout the year:
Corridor looks like this
Starting at week 1, choose a random model for the week from the list of allowed models -> Based on the choice modify the list of allowed models for next weeks
If our choice satisfies the criterion (also lies within a corridor), then week+=1. If not, delete this possibility.
If there is no more models for this week, go back one week, delete the possibility we have chosen before and choose random from what's left.
Pictorially the algorithm is like following the branches of a tree. If the branch is bad, return back to the fork and cut off the bad branch.
This algorithm can generate a random valid solution (in about 5 to 80 minutes with a mean time of 25 minutes). Then I need to generate more of those and choose one that has the least weight. Which is not a very good approach, I presume.
Question
The question is: what is the optimal way to solve the problem? The priority is to find the solution with a minimal weight and a target value and not the fastest algorithm. But it should at least end in a final amount of time =)
The problem statement above is a bit oversimplified and due to the complexity of calculations and the amount of combinations, there is no way to consider and compare all combinations.

Dynamic Programming - Job Selection

I am attempting at solving a Job Selection problem using Dynamic Programming. The problem is as follows:
- There is one job offering every day with varying payouts every day
- You cannot work three days in a row (if you work on day 1 and 2, you must take a break on day 3)
- Come up with a job schedule to work on to maximize the amount of money you make
I have formalized the input and output of the problem as follows:
Input: P[1...n] a list of n positive numbers
Output: m, a max possible payout and A, a set of indexes {1,... n} such that if i is in A, and i+1 is in A, then i+2 is not in A. m is equal to a summation of P[i] for all values i in set A.
I am stuck on the thought process of making a self-reduction, and subsequently a dynamic programming algorithm in order to calculate the maximum earnings.
Any assistance is highly appreciated - thanks!
Usually dynamic programming is relatively straightforward once you decide how much state you need to take account of at each point, and your solution is efficient or not depending on whether your choice of state is good.
Here I would suggest that the state at each point is whether it is 0, 1, or 2 days since the last break. So for each day and 0,1,2 days since a break I calculate the max possible payout up to and including that day, given that it is 0,1,2 days since a break.
For 0 days since a break the max payout is the max possible payout for any state on the previous day. There is no contribution for that day, since you are taking a break.
For 1 days since a break the max payout is the payout for that day plus the max possible pay from all previous days for the state of 0 days since a break for that day.
For 2 days since a break the max payout is the payout for the current and previous days plus the max possible payout for two days ago and a state of 0 days since the last break on that day.
So you can calculate the max payouts from left to right, making use of previous calculations, and the overall max is the max payout associated with any state on the final day.
I think it would be easier to formule the answer in this way:
Solutions:
X=[x1, x2, ..., xn] in [0,1]^n | xi + xj + zk <= 2 for each k=i+2=j+1, i>=1, k<=n.
Maximize:
f(X)= Sum(xi*vi) for i in [1, N], where vi is the payout of working day i.
Then recursive algorithm has to decide wether if it works a day or if not to maximize the function, taking into acount the restraints of Solution. That is a very simple basic schema for DP.
Mcdowella explains the choice of states and transitions pretty well for this particular DP problem. The only thing left to add is a graph representation. Hope it helps.
Job Selection DP

Group Maker Algorithm based on free time avaliable

I am trying to come up with an algorithm that would make groups based on the maximum free time available a group of people have in polynomial time, but I believe the solution to this problem might be NP.
The problem is as followed:
We divided the week into 1 hour slots where users can put down for each slot whether they are free or busy. Let's say we gather this information from 30 users. Let's also assume that users%group_size = 0
First:
Is it possible to put these people into groups of size G so that every member in each group of size G has one overlapping free time slot with each other?
Is it possible to put these people into groups of size G that results in an optimal solution, which is to have the maximum total overlapping free time slots among all groups?
For example, if we had a group of 6 people with the following free time:
A: 1pm-3pm Sunday AND 1pm-3pm Monday
B: 2pm-3pm Sunday AND 1pm-3pm Monday
C: 1pm-3pm Sunday AND 7pm-9pm Monday
D: 6pm-7pm Sunday AND 7pm-9pm Monday
E: 5pm-7pm Sunday AND 7pm-9pm Monday
F: 6pm-7pm Sunday AND 1pm-3pm Monday
The algorithm would determine that A,B,F would be one group and C,D,E would be another group because a maximum of two hours of free time overlaps between the groups. This is opposed to A,B,C and D,E,F which only contains 1 overlapping time slot for every member in the group. As a result, this is optimal solution which is greatest overlap in total among all groups.
I realized this problem is probably related to the Hopcroft-Karp Algorithm, but needs to be modified greatly to accomplish this task. Is their another algorithm that relates more closely to the solution then the Hopcroft-Karp Algorithm? Can this solution be achieved in polynomial time?
Background:
We have a bunch of people(30-50) who want to volunteer for a cause and they only have certain times they are free during the week. We want to break them into groups of 3-5 and have them work together for this cause. We want the group members to have as much time as possible with each other so we want to break them into groups where they have similar free times available.
Thanks a bunch and please let me know if this is an obvious question or if more clarification is needed.
On first look, it seems like a set cover problem, where a subset is number of persons sharing a time slot and the universal set would be all the persons.
U = {p0, p1, p2 ..... , p29} // Number of persons.
S = {S0, S1, S2, ....... S23} // number of 1 hour slots.
I am still not sure how to use the G(size of a ideal group) into account.

Event Scheduling Greedy

We are given N ranges of date offsets when N employees are present in an
organization. Something like
1-4 (i.e. employee will come on 1st, 2nd, 3rd and 4th day )
2-6
8-9
..
1-14
We have to organize an event on minimum number of days such that each
employee can attend the event at least twice.Please suggest the algorithm(probably greedy) to do this.
PS: Event is one day event.
If your data is small, you can just brute-force it. Pick all possible combination of 2 days. For each combination, try it and see if everyone can attend both. If not, pick all possible combinations of 3 days, see if everyone can attend 2 out of the 3, and so on. It's exponential, but may not be so bad for your purposes.
The greedy approach is to count how many people are at work each day, and pick the day with the maximum number of people. Repeating, count how many people are at work each day who don't already have two events scheduled and pick the day with the maximum number of people. Of course, don't pick the same day twice.
I think this can be done by the following greedy approach on events sorted with end date
Maintain a num count for all intervals. (Initialize all to 0)
If num = 0 place the two events on the last two days of this interval.
If num = 1 place one event on the last day of this interval
If num = 2 already two events have been covered for this interval.
Placing on the event in an interval can lead to increase in num count of the succeeding event.

Resources