之前,我们已经讨论了一种最小化损失的策略:作业排序问题–最小化损失。在本文中,我们将研究适用于稍有不同的问题的另一种策略。
我们给了N个生产商品的序列,编号从1到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有什么好处
第一天后的损失: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