独立任务最优调度问题

附注:以下算法描述是从网友博客上转的,附录程序是自己改动的。

问题描述:独立任务最优调度,又称双机调度问题:用两台处理机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;     
    } 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
这是一个经典的动态规划问题,可以使用C语言实现。以下是一种可能的解决方案: 1. 定义状态:设f(i,j)表示前i个任务放在j张加密卡上的最小花费。 2. 状态转移方程:考虑第i个任务,它可以独立放在一张加密卡上,也可以与前面的任务一起放在一张加密卡上。因此,有以下两种情况: 1) 第i个任务独立放在一张加密卡上,那么前i-1个任务就需要放在j-1张加密卡上,此时状态转移方程为: f(i, j) = min(f(i-1, j), f(i-1, j-1)) + cost(i) 2) 第i个任务与前面的任务一起放在一张加密卡上,那么前i-1个任务就需要放在j张加密卡上,此时状态转移方程为: f(i, j) = f(i-1, j) + cost(i) 其中,cost(i)表示第i个任务的花费。 3. 边界条件:当i=1时,只需要考虑前1个任务放在1张加密卡上的情况,即f(1,1)=cost(1)。当j=1时,只能将前i个任务都放在1张加密卡上,即f(i,1)=f(i-1,1)+cost(i)。 4. 最终答案:最小花费为min(f(n,1), f(n,2), f(n,3), f(n,4)),其中n为总任务数。 下面是C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> #define MAX_TASKS 100 #define MAX_CARDS 4 int min(int a, int b) { return a < b ? a : b; } int main() { int n, i, j, k, cost[MAX_TASKS + 1], f[MAX_TASKS + 1][MAX_CARDS + 1]; // 读入任务数和每个任务的花费 scanf("%d", &n); for (i = 1; i <= n; i++) { scanf("%d", &cost[i]); } // 初始化边界条件 for (i = 1; i <= n; i++) { f[i][1] = f[i-1][1] + cost[i]; } for (j = 1; j <= MAX_CARDS; j++) { f[1][j] = cost[1]; } // 动态规划求解 for (i = 2; i <= n; i++) { for (j = 2; j <= MAX_CARDS; j++) { f[i][j] = f[i-1][j] + cost[i]; for (k = 1; k < i; k++) { f[i][j] = min(f[i][j], f[k][j-1] + cost[i]); } } } // 输出最小花费 int ans = f[n][1]; for (j = 2; j <= MAX_CARDS; j++) { ans = min(ans, f[n][j]); } printf("%d\n", ans); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值