5 CPU的任务调度N过程

时间:2018-06-15 07:30:12

标签: c++ algorithm dynamic-programming

问题。

  

队列中有5个CPU和N个任务。你必须使用   处理任务的最小CPU。

     

任务的格式为[到达时间,处理任务的时间]。

     

注意:

     
      
  1. 您最多只能使用5个CPU。如果在5个CPU中不可用,则打印-1。

  2.   
  3. 处理任务的时间不应大于10,即(队列中等待的时间+处理任务的时间)< = 10。

  4.   
  5. 如果要处理当前任务,当前CPU需要10秒以上,可以移动到不同的CPU并检查是否是   可以在< = 10时间内处理任务。

  6.   
  7. 如果无法在< = 10或最多5个CPU中处理任务,请打印-1。

  8.   

约束。

  

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)秒内完成,没有任何时间在队列中等待。

我的方法:

  1. 最初,我认为这是minimum train-platform problem的变体。但这是错误的。

  2. 尝试了一种greedy方法,但它为一些有效的解决方案提供了-1。

  3. 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;
    
    
    }
    
    1. 尝试memoization方法。
    2. 递归方法可以解决问题,但它会超时。 (难怪)

      保存intintint[]状态的可行方法是什么?

      我也愿意接受相同的迭代解决方案。

      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调度无关。

1 个答案:

答案 0 :(得分:0)

摘要:强制应答(最大CPU数),按开始时间对任务进行排序,使用带有配置文件的DP按顺序将它们分配给CPU(配置文件是特定CPU的最近时刻)可用;忽略CPU的顺序。)

解决方案相当复杂。随意请求澄清。

创意1 :让我们蛮力最大数量的CPU并强制它(或应用二进制搜索: 如果A CPU足够,那么A+1 CPU就足够了)。 现在我们有固定数量的CPU,我们必须解决是/否问题:是吗 有可能以这样的方式安排任务执行吗? 由于我们最多有5个CPU,因此可以使用简单的外部for循环实现该想法。

创意2 :有一个解决方案可以在整数时刻开始处理任何任务。

证明:采取任何解决方案,选择该条件不适用的最左边的任务, 并注意到可以将它进一步向左移动。 这减少了所有任务的总位置。 现在让我们选择最小化该值的解决方案。 它不能有任何以非整数时间开始的任务。

构思3 :每个CPU都有以下条件的解决方案: 对于每个尝试任务ABAB之前执行, A出现在B之前的排序任务列表中(按到达/创建时间排序)。

证明:在每个CPU上执行任意解决方案和冒泡排序任务。 我们必须证明交换两个相邻的任务不会使解决方案不正确。 考虑任务AB,以便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循环中愉快地粉碎它。 当然,最好是预先计算配置文件之间的转换,但它 也可能没有那个。