zoukankan      html  css  js  c++  java
  • 独立任务最优调度问题

    问题描述:独立任务最优调度,又称双机调度问题:用两台处理机A和B处理n个作业。设第i个作业交给机器A处理时所需要的时间是a[i],若由机器B来处理,则所需要的时间是b[i]。现在要求每个作业只能由一台机器处理,每台机器都不能同时处理两个作业。设计一个动态规划算法,使得这两台机器处理完这n个作业的时间最短(从任何一台机器开工到最后一台机器停工的总的时间)。研究一个实例:n=6, a = {2, 5, 7, 10, 5, 2}, b = {3, 8, 4, 11, 3, 4}.

    分析:当完成k个作业,设机器A花费了x时间,机器B所花费时间的最小值肯定是x的一个函数,设F[k][x]表示机器B所花费时间的最小值。则F[k][x]=Min{ F[k-1][x]+b[k], F[k-1][x-a[k]] };其中F[k-1][x]+b[k]表示第k个作业由机器B来处理(完成k-1个作业时机器A花费的时间仍是x),F[k-1][x-a[k]]表示第k个作业由机器A处理(完成k-1个作业时机器A花费的时间是x-a[k])。

          那么单个点对较大值Max(x, F[k][x]),表示此时(即机器A花费x时间的情况下)所需要的总时间。而机器A花费的时间x是变化的,即x=0,1,2……x(max),(理论上x的取值是离散的,但为编程方便,设为整数连续的)由此构成了点对较大值序列。要求整体时间最短,取这些点对较大值序列中最小的即是。

        理解难点在于B是A的函数表达式,也即动态规划所在。花点时间,看懂表达式,加上思考,理解了这点一切OK,后面的编程实现完全依据这个思想。先用前两个任务的枚举示例来帮助理解。

    示例:前两个作业示例足矣。

    初始化第一个作业:下标以0开始。

    首先,机器A所花费时间的所有可能值范围:0 <= x <= a[0].
    设x<0时,设F[0][x]= ∞,则max(x, ∞)= ∞;记法意义见下。
    x=0时,F[0][0]=3,则Max(0,3)=3,机器A花费0时间,机器B花费3时间,而此时两个机器所需时间为3; 
    x=1时,F[0][1]=3,Max(1,3)=3;
    x=2时,F[0][2]=0,则Max(2,0)=2;

    那么上面的点对序列中,可以看出当x=2时,完成第一个作业两台机器花费最少的时间为2,此时机器A花费2时间,机器B花费0时间。

    来看第二个作业:

           首先,x的取值范围是:0 <= x <= (a[0] + a[1]).
           当x<0时,记F[1][x] = ∞;这个记法编程使用,因为数组下标不能小于0。在这里的实际含义是:x是代表完成前两个作业机器A的时间,a[1]是机器A完成第2个作业的时间,若x<a[1],则势必第2个作业由机器B来处理,即在Min()中取前者。

    x=0,则F[1][0]= Min{ F[0][0]+b[2], F[0][0-a[1]] }= Min{3+8,∞}=11,进而Max(0,11)=11;
    x=1,则F[1][1]= Min{ F[0][1]+b[2], F[0][1-a[1]] }= Min{3+8,∞}=11,进而Max(11)=11;
    x=2,则F[1][2]= Min{ F[0][2]+b[2], F[0][2-a[1]] }= Min{0+8,∞}=8,进而Max(2,8)=8;
    x=3,则F[1][3]= Min{ F[0][3]+b[2], F[0][3-a[1]] }= Min{0+8,∞}=8,进而Max(3,8)=8;
    x=4,则F[1][4]= Min{ F[0][4]+b[2], F[0][4-a[1]] }= Min{0+8,∞}=8,进而Max(4,8)=8;
    x=5,则F[1][5]= Min{ F[0][5]+b[2], F[0][5-a[1]] }= Min{0+8,3}=3,进而Max(5,3)=5;
    x=6,则F[1][6]= Min{ F[0][6]+b[2], F[0][6-a[1]] }= Min{0+8,3}=3,进而Max(6,3)=6;
    x=7,则F[1][7]= Min{ F[0][7]+b[2], F[0][7-a[1]] }= Min{0+8,0}=0,进而Max(7,0)=7;

    那么上面的点对序列中,可以看出当x=5时,完成两个作业两台机器花费最少的时间为5,此时机器A花费5时间,机器B花费3时间。

    算法时间复杂度:按照上述思想,编程实现,结果如上图,算法时间复杂度为O(n*Sum),其中Sum为a中所有元素之和与b中所有元素之和的最小值。王晓东《算法设计与实验题解》中提供的方法时间复杂度是O(m*m*n*n*n),其中m为a、b所有元素的最大值。
          比较:Sum必然远远小于n*m;所以n*Sum<n*n*m,相比之下差了O(n*m)都不止,看来这个思想还是蛮优秀的。。。。

    程序如下,数据通过“input.txt”输入:

    #include<iostream> 
    #include<fstream>
    #include<iomanip>  
    using namespace std;  
    const int SIZE=50;  
    const int MAXINT=999;  
    int main(){  
          
    while(1){  
    int N,a[SIZE],b[SIZE],SumA[SIZE],SumB[SIZE];  
    int tempSumA,tempSumB,MinSum;  
    int i=0,j,k;  
    tempSumA=tempSumB=0;
    int data;
    int oriData[SIZE]; 
    //记录A,B完成当前任务所需时间  
    //Read input.txt
     ifstream ifile;
        ifile.open("input.txt");  
     if(ifile.eof()) 
        {
            cerr<<"Fail to open the file input.txt"<<endl;
            return 1;
        }
    while(ifile>>data)
        {
      oriData[i++]=data;    //Recording data
        }

     N=(int)oriData[0];    //the number of task
    // i=0;
     for (i=1;i<=N;i++)
     {
      a[i]=oriData[i];
      tempSumA+=a[i];  
      SumA[i]=tempSumA;
     }
     for (i=1,j=N+1;j<=2*N;j++,i++)
     {
      b[i]=oriData[j];
      tempSumB+=b[i];  
      SumB[i]=tempSumB;
     }

     //Show data of input.txt and data will process.
     cout<<"Input.txt Data:"<<endl;
     cout<<oriData[0]<<endl;
     for (i=1;i<=2*N; )
     {
      cout<<oriData[i]<<" ";
      i++;
      cout<<oriData[i]<<endl;
      i++;  
     }
    /* cout<<"Data will process:"<<endl;
     for (i=0;i<cnt;i++)
     {
      cout<<proData[i]<<" ";
     }*/
     cout<<endl;
        ifile.close();
    /*cin>>N;  
    if(N<=0)break;  
    int tempSumA,tempSumB,MinSum;  
    int i,j,k;  
    tempSumA=tempSumB=0;  
    for(i=1;i<=N;i++){  
    cin>>a[i];  
    tempSumA+=a[i];  
    SumA[i]=tempSumA;  
    }  
    for(i=1;i<=N;i++){  
    cin>>b[i];  
    tempSumB+=b[i];  
    SumB[i]=tempSumB;  
    }  */
    MinSum=(tempSumB>tempSumA)?tempSumA:tempSumB;  
    //时间上限AB总和的最小值  
    ///动态二维数组   
    int *MaxTime=new int [MinSum+1];  
    int **F=new int*[N+1];  
    for(i=0;i<N+1;i++)  
    F[i]=new int [MinSum+1];  
    SumB[0]=0;  
    for(i=0;i<=N;i++){  
    F[i][0]=SumB[i];//SumB[0]没赋值,调试时会输出地址   
    for(j=1;j<=MinSum;j++)  
    F[i][j]=0;  
    }  
    /*for(i=0;i<=N;i++){ 
    for(j=0;j<=MinSum;j++) 
    cout<<setw(2)<<F[i][j]<<" "; 
    cout<<endl; 

    cout<<endl;*/  
    int temp;  
    for(k=1;k<=N;k++){  
       temp=(SumA[k]>SumB[k])?SumB[k]:SumA[k];  
       for(i=1;i<=temp;i++){ //A最多用AB前k任务的最小值,如果B最少就全用B做。  
          if(i>=a[k])//等于号不能少   
        F[k][i]=(F[k-1][i]+b[k]<F[k-1][i-a[k]])?F[k-1][i]+b[k]:F[k-1][i-a[k]];  
          else F[k][i]=F[k-1][i]+b[k];  
                            }   
                      }  
                        
    /*for(i=0;i<=N;i++){ 
    for(j=0;j<=MinSum;j++) 
    cout<<setw(2)<<F[i][j]<<" "; 
    cout<<endl; 
                      } 
    cout<<endl;      */  
            
    temp=MAXINT;  
    for(i=0;i<=MinSum;i++){  
     MaxTime[i]=(i>F[N][i])?i:F[N][i];  
    if(temp>MaxTime[i])  
    temp=MaxTime[i];  
                           }  
    //cout<<temp<<endl;

    //out.txt
    ofstream ofile;  //write file
     ofile.open("output.txt");
    /* int result=0;
     for(int i=0;i<c;i++)
     {
      result+=abs(Data[i]-m);
     }*/
     ofile<<temp<<endl;
    ofile.close();
    cout<<"最优时间为:"<<temp<<endl;
    while(1);
    ///////////////////////////////////  
    /*for(i=0;i<N+1;i++)  
    delete [] F[i];  
    delete [] F;  
    delete [] MaxTime;  
    F=NULL;   */
    }  
    ////////////////////////////////  
    //system("pause");  
    //return 0;      
        }  

  • 相关阅读:
    LINUX核心命令实战总结七——文件备份与压缩命令
    LINUX核心命令实战总结六——信息显示与搜索文件命令
    LINUX核心命令实战总结五——文件过滤及内容编辑处理命令二
    LINUX核心命令实战总结四——文件过滤及内容编辑处理命令一
    LINUX核心命令实战总结三——文件和目录操作命令二
    LINUX核心命令实战总结二——文件和目录操作命令一
    LINUX核心命令实战总结一——关机、重启、注销命令
    python进阶十——mysql初识
    python进阶九——并发编程之协程
    入职培训第一天
  • 原文地址:https://www.cnblogs.com/is-zj/p/3740207.html
Copyright © 2011-2022 走看看