问题。
队列中有5个CPU和N个任务。你必须使用 处理任务的最小CPU。
任务的格式为[到达时间,处理任务的时间]。
注意:
您最多只能使用5个CPU。如果在5个CPU中不可用,则打印-1。
处理任务的时间不应大于10,即(队列中等待的时间+处理任务的时间)< = 10。
如果要处理当前任务,当前CPU需要10秒以上,可以移动到不同的CPU并检查是否是 可以在< = 10时间内处理任务。
- 醇>
如果无法在< = 10或最多5个CPU中处理任务,请打印-1。
约束。
0 <=到达时间&lt; = 500
1&lt; =处理任务的时间&lt; = 10
0 <= N <= 500
您只能使用iostream库。不允许STL。
时间:T测试案例为3秒
如: -
输入
3
1 6
2 7
3 1
输出
2
说明:
3 - N
1 6 - 第一个任务在时间1到达CPU0,在时间7(1 + 6)离开。 使用的CPU = 1.
2 7 - 第二个任务在时间2到达CPU0,等待5 队列中的秒数,因此总处理时间为5 + 7> 1。 10.就是这样 转移到CPU1。使用的CPU = 2。
3 1 - 第三项任务到来。它可以转到CPU0或CPU1,如 处理时间分别为5
( (7-3) + 1 )
和7( (9-3) + 1 )
秒。使用的CPU = 2。CPU1是一个全新的CPU。因此task2将在9
(2 + 7)
秒内完成,没有任何时间在队列中等待。
我的方法:
最初,我认为这是minimum train-platform problem
的变体。但这是错误的。
尝试了一种greedy
方法,但它为一些有效的解决方案提供了-1。
CODE:
#include <iostream>
using namespace std;
#define MAXN 500
int N;
int arr[MAXN];
int len[MAXN];
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin>>N;
for(int i=0;i<N;i++){
cin>> arr[i] >> len[i];
}
int exit_time_of_task_in_CPUs[5]={0};
int cpus_used_so_far=1;
int min_processing_time;
int min_processing_time_idx;
for(int task_idx=0; task_idx<N; task_idx++){
min_processing_time = INT_MAX;
min_processing_time_idx = -1;
// finds the CPU which can process task in minimum time.
for(int i=0; i<cpus_used_so_far ; i++){
int processing_time = 0;
int time_in_queue = exit_time_of_task_in_CPUs[i] - arr[task_idx];
if( time_in_queue < 0 ) // ie processor is free before arrival
time_in_queue = 0;
processing_time = time_in_queue + len[task_idx];
if( processing_time <=10){
if(processing_time < min_processing_time){
min_processing_time = processing_time;
min_processing_time_idx = i;
}
}
}
if( min_processing_time_idx == -1){
// No Existing CPU can solve this task.
// Check if spawning a new CPU is possible.
if (cpus_used_so_far+1 <= 5){
//spawn a new CPU
cpus_used_so_far++;
int new_cpu_index = cpus_used_so_far - 1; // last CPU, converting to zero index
exit_time_of_task_in_CPUs[new_cpu_index] = arr[task_idx] + len[task_idx] ;
}else{
cpus_used_so_far = -1; // not possible to spawn a new CPU,
break; //and you can't process with existing CPUs
}
}else{
// Possible to handle with existing CPUs
exit_time_of_task_in_CPUs[min_processing_time_idx] = arr[task_idx] + min_processing_time;
}
}
cout << cpus_used_so_far <<endl;
}
memoization
方法。 递归方法可以解决问题,但它会超时。 (难怪)
保存int
,int
,int[]
状态的可行方法是什么?
我也愿意接受相同的迭代解决方案。
CODE:
#include <iostream>
using namespace std;
#define MAXN 500
int min_cpus_used = 6;
int N;
int arr[MAXN];
int len[MAXN];
void recurse( int task_idx, int cpus_used_so_far, int exit_time_of_task_in_CPUs[] ){
if( task_idx == N-1){
min_cpus_used = min( min_cpus_used, cpus_used_so_far);
return ;
}
if( cpus_used_so_far >= min_cpus_used ){
return ; //optimization
}
for(int i=0; i<cpus_used_so_far ; i++){
int processing_time = 0;
int time_in_queue = exit_time_of_task_in_CPUs[i] - arr[task_idx];
if( time_in_queue < 0 ) // ie processor is free before arrival
time_in_queue = 0;
processing_time = time_in_queue + len[task_idx];
// try with existing CPUs
if( processing_time <=10){
int prev = exit_time_of_task_in_CPUs[i];
exit_time_of_task_in_CPUs[i] = arr[task_idx] + processing_time;
recurse( task_idx + 1 , cpus_used_so_far , exit_time_of_task_in_CPUs ); // can we optimize passing array
exit_time_of_task_in_CPUs[i] = prev;
}
// try with new CPU
if (cpus_used_so_far+1 <= 5){
int new_cpu_index = cpus_used_so_far + 1 - 1; // converting to zero index
int prev = exit_time_of_task_in_CPUs[new_cpu_index];
exit_time_of_task_in_CPUs[new_cpu_index] = arr[task_idx] + len[task_idx] ;
recurse( task_idx+1 , cpus_used_so_far+1 , exit_time_of_task_in_CPUs );
exit_time_of_task_in_CPUs[new_cpu_index] = prev;
}else{
return ;
}
}
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin>>N;
for(int i=0;i<N;i++){
cin>> arr[i] >> len[i];
}
int exit_time_of_task_in_CPUs[5]={0};
recurse(0, 1, exit_time_of_task_in_CPUs);
if(min_cpus_used==6){
cout<< -1 <<endl;
}else{
cout << min_cpus_used <<endl;
}
}
请帮助我考虑优化此解决方案。
PS:这与CPU调度无关。
答案 0 :(得分:0)
摘要:强制应答(最大CPU数),按开始时间对任务进行排序,使用带有配置文件的DP按顺序将它们分配给CPU(配置文件是特定CPU的最近时刻)可用;忽略CPU的顺序。)
解决方案相当复杂。随意请求澄清。
创意1 :让我们蛮力最大数量的CPU并强制它(或应用二进制搜索:
如果A
CPU足够,那么A+1
CPU就足够了)。
现在我们有固定数量的CPU,我们必须解决是/否问题:是吗
有可能以这样的方式安排任务执行吗?
由于我们最多有5个CPU,因此可以使用简单的外部for循环实现该想法。
创意2 :有一个解决方案可以在整数时刻开始处理任何任务。
证明:采取任何解决方案,选择该条件不适用的最左边的任务, 并注意到可以将它进一步向左移动。 这减少了所有任务的总位置。 现在让我们选择最小化该值的解决方案。 它不能有任何以非整数时间开始的任务。
构思3 :每个CPU都有以下条件的解决方案:
对于每个尝试任务A
和B
,A
在B
之前执行,
A
出现在B
之前的排序任务列表中(按到达/创建时间排序)。
证明:在每个CPU上执行任意解决方案和冒泡排序任务。
我们必须证明交换两个相邻的任务不会使解决方案不正确。
考虑任务A
和B
,以便A
在排序列表中B
之后。
这意味着它的创建时间不会超过B
的创建时间,
所以我们开始处理B
时存在A
。
这也意味着A
所需的终止时间不会超过B
的创建时间,
因此,在B
完成时,我们仍然可以完成A
。
因此,交换他们的执行顺序并不会使解决方案不正确
我们可以自由地这样做。
创意4 :可以通过从空执行开始构建解决方案 计划所有CPU,然后逐个将任务逐个添加到某些计划中 从最早到达并完成最新到达的任务。 我们将任务附加到可以在给定CPU上启动的最短时间。
证明:使用构思3中的属性采取任意解决方案。 请注意,每个CPU的执行计划是已排序的任务列表的子序列。 那么,这意味着可以将排序列表中的每个任务分配给CPU, 在从概念4执行算法之后,我们将最终得到一些执行计划。 它将“不比我们原来的解决方案更糟糕”:所有任务的位置都不会 大于原计划中任务的位置。 因此,该计划也是一种解决方案。
构思5 :运行递归回溯以查找CPU之间的任务分布。 我们已经知道应该将它们添加到CPU中的顺序(创建顺序)。 跟踪每个CPU上的第一个可用时间和蛮力分配 搜索的每个步骤的下一个任务。例如。对于从零开始的长度为1,5,2,9,3的任务,分配可以是:
Task start: 0 0 0 0 0
Task length: 1 5 2 9 3
Assigned CPU: A B B A B
创意6 :添加memoization(也就是将回溯转换为动态编程)。
请注意,我们并不关心CPU上的第一个可用时间是否小于下一个
任务的开始时间X
,也不能大于X+10
。
因此,我们为每个CPU提供了11种可能性,即11^5=161051
种可能性
适用于5个CPU。
那是我们DP的“概况”。
由于我们不关心CPU的顺序,因此不同的配置文件的答案
通过排列只是相同的。
因此,我们只能考虑3003个不同的配置文件(即\choose{10+5}{5}
)。
我们州的另一个变量是下一个任务的数量(500种可能性),
我们还从每个状态(要使用的CPU)进行5次转换。
这使得3003*500*5 ~ 8m
过渡,这不是一个大数字,所以我们
我可以在创意1的外部for循环中愉快地粉碎它。
当然,最好是预先计算配置文件之间的转换,但它
也可能没有那个。