I'm trying to work through the following DP problem is as follows:
A employee at a car wash company has a goal of washing C total cars over the span of next D days. Because of restrictions with his schedule and supplies, he can only wash cars at most D i cars a day. Fortunately for him, he has been provided him a list of the maximum number of cars he can wash for each each day for the D days in advance such that [Day 1 = 2 cars, Day 2 = 3 cars, Day 3 = 4 cars). How many many different ways can he meet his goal of washing C cars over the span of D days so that the sum of the total cars over those days equal C. He must wash at least 1 car a day. He cannot meet his goal in a # of days < D so it must be done exactly within D days.
For example, if he has a goal of C = 5 cars and it must be done in 3 days D = 3 with the max limits of {2, 3, 4} cars that can be washed each day, the total number of ways he can wash cars would be 5. These 5 ways would be the following combinations:
[1 1 3]
[1 3 1]
[2 2 1]
[2 1 2]
[1 2 2]
I've tried to write the pseudo code and recursion relation using the iterative bottom-up approach but I'm not really sure how to store and track the # of total ways you can wash cars at each sub-problem [i][j]
def findWays(T, D, limits):
M = [[0]*(T+1) for i in range(D+1)]
for i in range(1, D+1):
dayLimit = limits[i-1]
for j in range(1, T+1):
if i == 1:
if j <= dayLimit:
M[i][j] = 1
else:
for k in range(1, j):
if (j - k) > dayLimit:
continue
if (dayLimit - M[i-1][k]) >= 1:
M[i][j] = M[i][j] + M[i-1][k]
print(M)
Here is dynamic programming solution that works in O(D*C*C)
time;
Sample matrix for D=3, C till 10 with [2, 3, 4] limits.
int NumberOfWays(int c, int d, int[] limits)
{
// let's t[i, j] be amount of ways j cars can be washed in i days
var t = new int[d + 1, c + 1];
for (int day = 1; day <= d; day++)
{
int dayLimit = limits[day - 1];
for (int cars = day; cars <= c; cars++)
{
if (day == 1) // first day
{
if (cars <= dayLimit)
t[day, cars] = 1;
} else // not first day
{
// okay, number of ways given amount of cars can be washed
// on certain day can be calculated using amounts possible on the previous day
for (int carsOnPrevDay = 1; carsOnPrevDay < cars; carsOnPrevDay++)
{
if (cars - carsOnPrevDay > dayLimit)
continue; // day limit exceeded
t[day, cars] += t[day - 1, carsOnPrevDay];
}
}
}
}
return t[d, c];
}
Note: the problem is the same as another common one: how many ways are there of rolling a given total using dice with d1, d2, d3, ..., dn sides.
If there's C[n, i] ways of washing n cars in i days, there's sum(C[nk], i+1), k = 1..D[i+1]) ways of washing n cars in i+1 days. With the edge conditions: C[0, 0] = 1, C[0, _] = 0.
This directly gives this O(Cmax(D)|D|) algorithm, which uses O(C) space.
def cars(C, D):
r = [1] + [0] * C
for d in D:
for i in range(C, -1, -1):
r[i] = sum(r[j] for j in range(max(0, i-d), i))
return r[C]
print(cars(5, [2, 3, 4]))
You can do a little better, since the inside loop is performing a rolling sum of d values, which can be computed in O(1) time per element of C on average.
def cars(C, D):
r = [1] + [0] * C
for d in D:
S = 0
for i in range(C, -d-1, -1):
if i >= 0:
S += r[i]
if i + d <= C:
S -= r[i+d]
r[i+d] = S
return r[C]
print(cars(5, [2, 3, 4]))
Since without loss of generality, max(D) < C, this is O(C|D|) and still uses O(C) space.
If it helps, this code is essentially computing the first C+1 terms of the polynomial P[D[0]] * P[D[1]] * ... * P[D[len(D)-1]], where P[d] = x + x^2 + ... + x^d. The coefficient of x^C in the result is the solution to your problem.
On a more educational note, I tried manually running through your algorithm (ignoring the bounding issues) and got this matrix:
But you're probably looking more for this (note that I neglected to fill in the invalid values due to laziness):
Look into adjusting your summation a bit, particularly on that first day where for some reason it's not possible to wash 2 or 3 cars. Afterwards, you're correct in returning OPT[D, C]
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.