分配工人任务的动态规划算法
Dynamic Programming algorithm for assigning workers to tasks
假设您的任务是将 m 名工人分配给 n 项任务。你能够计算出第 i 个工人会给任务 j 带来多少“收益”。或者更正式地说:每个任务都有一个数组 A_j[0..m],其中 A_j[i] 是将 i 名员工分配给任务 j 所获得的收益。我们可以假设 A_j[i] 不随着 i 的增加而减少。
我正在尝试设计一个动态规划算法来确定您应该为每个项目分配多少工人,以使所有项目获得的总收益最大化。
不幸的是,我似乎无法弄清楚如何解决这个问题,因为“子问题”似乎彼此完全无关(一个人的答案不会告知另一个人的答案)。例如,鉴于我编写的这个“测试用例”:
- 如果给 3 个人,最大收益 B 将为:B = 15 = T4_1 + T2_2
- 如果给4个人,:B = 100 = T1_4
蛮力方法需要指数时间,因为每次给你一个工人,你都有 n 个可能的任务作为分配给他们的选项。鉴于我的测试示例,可以以 4 种可能的方式分配 1 个工人。可以用 16 种可能的方式分配 2 个工人。 64 中的 3,等等。因此,蛮力复杂度为 O(n^m)。
在解决动态规划 (DP) 问题时,我通常更喜欢使用制表策略,而不是记忆。 有没有办法用DP制表的方式建一个数组来解决这个问题?
动态规划算法的状态为DP[i][j],表示分配i[=55可以获得的最大收益=] 工人到第一个 j 个项目。
我们来看看这样一个算法的伪代码:
int DP[m+1][n+1] = { 0 };
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
// try to assign k workers to the jth project
for(int k = 1; k <= i; k++){
DP[i][j] = max(DP[i][j], profit[k][j] + DP[i - k][j - 1]);
}
}
}
首先,我们创建大小为nxm的动态规划数组。接下来,我们遍历 i 和 j.
的所有可能值
对于每对i和j,我们需要计算分配i[=55的最佳利润=] 工人到第一个 j 个项目。为了计算这个,我们应该尝试将 k 名工人分配给 jth 项目。如果我们分配k个工人到jth项目,那么我们需要使用profit[k][j] 表示在 jth 项目中使用 k 名工人的利润。
此外,我们需要添加 DP[i - k][j - 1] 的值,它代表使用 i-k[ 的最佳收益=55=] 个工人(如果我们使用 k 个工人,那么我们还剩下 i-k 个工人)在第一个 j-1 个项目。
完成后,您可以通过检查DP[w][n]的值来使用w个工人获得最大利润.
这种方法的时间复杂度是O(nxmxm),space复杂度是O(nxm) .
请注意,我们可以增强此方法,使其时间复杂度为 O(nxm),方法是进行一些计算以消除第三个 for循环。
假设您的任务是将 m 名工人分配给 n 项任务。你能够计算出第 i 个工人会给任务 j 带来多少“收益”。或者更正式地说:每个任务都有一个数组 A_j[0..m],其中 A_j[i] 是将 i 名员工分配给任务 j 所获得的收益。我们可以假设 A_j[i] 不随着 i 的增加而减少。
我正在尝试设计一个动态规划算法来确定您应该为每个项目分配多少工人,以使所有项目获得的总收益最大化。
不幸的是,我似乎无法弄清楚如何解决这个问题,因为“子问题”似乎彼此完全无关(一个人的答案不会告知另一个人的答案)。例如,鉴于我编写的这个“测试用例”:
- 如果给 3 个人,最大收益 B 将为:B = 15 = T4_1 + T2_2
- 如果给4个人,:B = 100 = T1_4
蛮力方法需要指数时间,因为每次给你一个工人,你都有 n 个可能的任务作为分配给他们的选项。鉴于我的测试示例,可以以 4 种可能的方式分配 1 个工人。可以用 16 种可能的方式分配 2 个工人。 64 中的 3,等等。因此,蛮力复杂度为 O(n^m)。
在解决动态规划 (DP) 问题时,我通常更喜欢使用制表策略,而不是记忆。 有没有办法用DP制表的方式建一个数组来解决这个问题?
动态规划算法的状态为DP[i][j],表示分配i[=55可以获得的最大收益=] 工人到第一个 j 个项目。
我们来看看这样一个算法的伪代码:
int DP[m+1][n+1] = { 0 };
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
// try to assign k workers to the jth project
for(int k = 1; k <= i; k++){
DP[i][j] = max(DP[i][j], profit[k][j] + DP[i - k][j - 1]);
}
}
}
首先,我们创建大小为nxm的动态规划数组。接下来,我们遍历 i 和 j.
的所有可能值对于每对i和j,我们需要计算分配i[=55的最佳利润=] 工人到第一个 j 个项目。为了计算这个,我们应该尝试将 k 名工人分配给 jth 项目。如果我们分配k个工人到jth项目,那么我们需要使用profit[k][j] 表示在 jth 项目中使用 k 名工人的利润。
此外,我们需要添加 DP[i - k][j - 1] 的值,它代表使用 i-k[ 的最佳收益=55=] 个工人(如果我们使用 k 个工人,那么我们还剩下 i-k 个工人)在第一个 j-1 个项目。
完成后,您可以通过检查DP[w][n]的值来使用w个工人获得最大利润.
这种方法的时间复杂度是O(nxmxm),space复杂度是O(nxm) .
请注意,我们可以增强此方法,使其时间复杂度为 O(nxm),方法是进行一些计算以消除第三个 for循环。