我正在尝试解决以下DP问题:
洗车公司的一名员工的目标是在接下来的D天之内洗净C辆汽车。由于日程安排和用品的限制,他一天最多只能洗D i 辆汽车。对他来说幸运的是,他已提前D天向他提供了每天最多可洗车的清单,例如[第1天= 2辆,第2天= 3辆,第3天= 4辆)。他可以在D天的时间内达到多少种清洗C辆汽车的目标,从而使这些天的总汽车总数等于C。他每天必须至少洗1辆汽车。他无法在D天后的几天内达到目标,因此必须在D天之内准确完成。
答案 0 :(得分:1)
这是一种动态编程解决方案,可以在O(D*C*C)
时间内工作;
D = 3,C到10的样本矩阵,其极限为[2,3,4]。
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];
}
答案 1 :(得分:1)
注意:问题与另一个常见问题相同:使用带有d1,d2,d3,...,dn边的骰子滚动给定总数的有几种方法。
如果在i天内有C [n,i]种方式清洗n辆汽车,那么有sum(C [nk],i + 1),k = 1..D [i + 1])方式清洗n辆汽车在i + 1天之内。在边缘条件下:C [0,0] = 1,C [0,_] = 0。
这直接给出了O(Cmax(D)| D |)算法,该算法使用O(C)空间。
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]))
您可以做得更好,因为内部循环正在执行d值的滚动总和,这可以平均用C的每个元素的O(1)时间来计算。
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]))
由于不失一般性,max(D) 如果有帮助,此代码实质上是在计算多项式P [D [0]] * P [D [1]] * ... * P [D [len(D)- 1]],其中P [d] = x + x ^ 2 + ... + x ^ d。结果中的x ^ C系数可以解决您的问题。
答案 2 :(得分:0)