我们之前讨论过一种损失最小化策略:作业排序问题——损失最小化。在本文中,我们将研究另一种适用于略有不同问题的策略。
给定一个从 1 到 N 编号的 N 个产品序列。每个产品都有一个用 (Vi) 表示的数量。限制是,一旦商品完成,其数量开始以每天固定的百分比 (P) 衰减。所有商品都以相同的速度衰减,而且每件商品都需要一天时间才能完成。
我们需要找出货物的生产顺序,以便使货物的总体积最大化。
示例 1:
Input: 4, 2, 151, 15, 1, 52, 12 and P = 10%
Output: 222.503
解:在最佳作业序列中,所有作业结束时剩余的货物总量为 222.503
示例 2:
Input: 3, 1, 41, 52, 15, 4, 1, 63, 12 and P = 20%
Output: 145.742
解:在最佳作业序列中,所有作业结束时剩余的货物总量为 145.72
解释 –
由于这是一个优化问题,我们可以尝试使用贪心算法来解决这个问题。每天我们都会从尚未生产的商品中进行选择。因此,我们所需要的只是一个本地选择标准或启发式方法,当应用于选择工作时,它将为我们提供最佳结果。
除了尝试最大化音量之外,我们还可以尝试最小化损失。由于从所有商品中可以获得的总体积也是恒定的,如果我们最大限度地减少损失,我们就可以保证得到最佳答案。
现在考虑任何具有体积 V 的商品
第 1 天后的损失:PV
第 2 天后的损失:PV + P(1-P)V 或 V(2P-P^2)
第 3 天后的损失:V(2P-P^2) + P(1 – 2P + P^2)V 或 V(3P – 3P^2 + P^3)
随着天数增加,损失也会增加。因此,诀窍是确保货物在生产后不会闲置。此外,由于我们需要每天至少生产一项作业,因此我们应该先执行低容量作业,然后再执行高容量作业。由于两个因素,该策略有效。
- 大批量商品在生产后不会闲置。
- 随着交易量的减少,每天的损失也会减少,因此对于小批量商品,几天后损失变得可以忽略不计。
因此,为了获得最佳解决方案,我们稍后会生产更大批量的商品。第一天选择产量最少的商品并生产。从货物清单中删除生产的货物。第二天重复同样的动作。当还有待生产的商品时,继续重复。
在计算生产结束时的总产量时,请记住第 i 天生产的商品将有
其剩余体积的倍数。显然,在第 N 天(最后一天)生产的商品的体积将保持不变,因为
算法 –
Step 1: Add all the goods to a min-heap
Step 2: Repeat following steps while Queue is not empty
Extract the good at the head of the heap
Print the good
Remove the good from the heap
[END OF LOOP]
Step 4: End
复杂性——
我们正好执行 N 个 push() 和 pop() 操作,每个操作都需要 log (N) 时间。因此,时间复杂度为 O( N * log(N) )。
下面是解决方案的实现。
C++
// C++ implementation of the
// above approach
#include
using namespace std;
void optimum_sequence_jobs(vector& V, double P)
{
int j = 1, N = V.size() - 1;
double result = 0;
// Create a min-heap (priority queue)
priority_queue, greater > Queue;
// Add all goods to the Queue
for (int i = 1; i <= N; i++)
Queue.push(V[i]);
// Pop Goods from Queue as long as it is not empty
while (!Queue.empty()) {
// Print the good
cout << Queue.top() << " ";
// Add the Queue to the vector
// so that total voulme can be calculated
V[j++] = Queue.top();
Queue.pop();
}
// Calclulating volume of goods left when all
// are produced. Move from right to left of
// sequence multiplying each volume by
// increasing powers of 1 - P starting from 0
for (int i = N; i >= 1; i--)
result += pow((1 - P), N - i) * V[i];
// Print result
cout << endl << result << endl;
}
// Driver code
int main()
{
// For implementation simplicity days are numbered
// from 1 to N. Hence 1 based indexing is used
vector V{ -1, 3, 5, 4, 1, 2, 7, 6, 8, 9, 10 };
// 10% loss per day
double P = 0.10;
optimum_sequence_jobs(V, P);
return 0;
}
Java
// Java implementation of the
// above approach
import java.util.*;
class GFG{
static void optimum_sequence_jobs(int[] V,
double P)
{
int j = 1, N = V.length - 1;
double result = 0;
// Create a min-heap
// (priority queue)
PriorityQueue Queue =
new PriorityQueue<>();
// Add all goods to the Queue
for (int i = 1; i <= N; i++)
Queue.add(V[i]);
// Pop Goods from Queue as
// long as it is not empty
while (!Queue.isEmpty())
{
// Print the good
System.out.print(Queue.peek() +
" ");
// Add the Queue to the vector
// so that total voulme can
// be calculated
V[j++] = Queue.peek();
Queue.remove();
}
// Calclulating volume of goods
// left when all are produced.
// Move from right to left of
// sequence multiplying each
// volume by increasing powers
// of 1 - P starting from 0
for (int i = N; i >= 1; i--)
result += Math.pow((1 - P),
N - i) * V[i];
// Print result
System.out.printf("\n%.2f\n",
result );
}
// Driver code
public static void main(String[] args)
{
// For implementation simplicity
// days are numbered from 1 to N.
// Hence 1 based indexing is used
int[] V = {-1, 3, 5, 4, 1,
2, 7, 6, 8, 9, 10};
// 10% loss per day
double P = 0.10;
optimum_sequence_jobs(V, P);
}
}
// This code is contributed by Amit Katiyar
输出 –
1 2 3 4 5 6 7 8 9 10
41.3811
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。