简体   繁体   中英

Dynamic Programming - Washing Cars

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM