算法设计与分析——独立任务最优调度问题

文章目录

  • 问题描述
  • 问题分析
    • 算法设计——动态规划
    • 最优子结构性质:
    • 构造最优解
    • 算法复杂度分析
  • 代码

问题描述

独立任务最优调度问题

问题描述:
用2台处理机A和B处理n个作业。设第i个作业交给机器A处理时需要时间ai.若由机器B来处理,则需要时间bi。由于各作业的特点和机器的性能关系,很可能对于某些i,有ai≥bi,而对于某些j≠i,有aj< bj;。既不能将一个作业分开由2台机器处理,也没有一台机器能同时处理2个作业。设计个动态规划算法,使得这2台机器处理完这n个作业的时间最短(从任何一台机器开工到最后一台机器停工的总
时间)。
研究一个实例:(a1,a2 ,a3,a4,a5,a5) = (2,5,7,10,5,2);
(b1,b2,b3,b4,b5,b6)= (3,8,4,11,3,4)。

算法设计:
对于给定的2台处理机A和B处理n个作业,找出一个最优调度方案,使2台机器处理完这n个作业的时间最短。

数据输入:
由文件input. txt提供输入数据。文件的第1行是1个正整数n,表示要处理n个作业,在接下来的2行中,每行有n个正整数,分别表示处理机A和B处理第i个作业需要的处理时间。
结果输出:
将计算出的最短处理时间输出到文件output txt。

输入文件示例
input. txt
6
2 5 7 10 5 2
3 8 4 11 3 4

输出文件示例

output. txt
15

问题分析

算法设计——动态规划

最优子结构性质:

设f[i][j]表示完成i个作业且机器A花费j时间的条件下机器B所花费时间的最小值,一定要注意这是B花费的时间。

可以往前递推一下,f[i][j]怎么得到的,也就是说当第i-1件任务完成后,第i件任务需要确定谁来做,这是一个子问题。

(1)若第i件任务由A来做,那么机器B花费的时间就是A完成前i-1个任务的时间(此时A还没有做第i件任务,所以花费的时间会比完成第i件任务少a[i])
即f[i-1][j-a[i]],相当于B没有做第i件任务,所以B花费的最短时间和做完第i-1件任务一样。

(2)若第i件任务由B来做,那么机器B花费的时间就是f[i-1][j]+b[i],也就是A完成了i-1个任务花费j时间的条件下加上B自己做第i件任务的时间。

为什么不需要像(1)那样减掉a[i]呢?因为第i件任务不是A做的,所以可以直接用j来代表A做完i-1件任务花的时间。

但是有一种情况是不能让A来做的,我们的j可以从0到sumA,其中sumA为假如按照所有的任务都由A来完成,A需要的时间的累加,比如说进行到第i件任务,那么sumA就是a[0]+a[1]+…+a[i]。如果完成i个任务花费的时间比A做第i个任务的时间还要少的话,即j

相当于你为了在10min内走完1km,如果你一直走,那么用时就会超过10min,所以后面一定要骑车,或者用更快的方式完成。在这种情况下,机器B花费的最少时间是f[i-1][j]+b[i];

由于两机器可以同时工作,A的运行对B的运行没有影响,确定了第i件任务由谁来完成,B花的时间最短,然后再从A和B中取得最晚的停机时间,就可以确定A和B完成任务的最短时间。所以问题满足最优子结构性质

构造最优解

6个任务
A机器完成时间2 5 7 10 5 2
B机器完成时间3 8 4 11 3 4

以前两个任务为例

第一个任务,0<=x<2,f[1][x]=b[1]是当A一直开机直到x,此时第一件任务只能由B来完成,因为A完成第一件任务至少需要2时间。
当x=a[1]时,比较A完成第一个任务的时间和B完成第一个任务的时间,如果A需要的时间更短,那么B根本不需要花时间完成第一个任务,f[1][2]就是0,否则第一件任务就给B来完成,B花费的最短时间就是b[1]

第二个任务往后,先初始化所有B花费的时间都是正无穷,然后计算sumA=a[1]+a[2]=7,
X=0,f[2][0]=f[1][0]+b[2]=b[1]+b[2]=11,max(0,11)=11;
X=1,f[2][1]=f[1][1]+b[2]=b[1]+b[2]=11,max(1,11)=11;
X=2,f[2][2]=f[1][2]+b[2]=0+b[2]=8,max(2,8)=8;
X=3,f[2][3]=f[1][3]+b[2]=0+b[2]=8,max(3,8)=8;
X=4,f[2][4]=f[1][4]+b[2]=0+b[2]=8,max(4,8)=8;
X=5,f[2][5]=min(f[1][5]+b[2],f[1][5-a[2]])=min(8,3)=3,max(5,3)=5;
X=6,f[2][6]=min(f[1][6]+b[2],f[1][6-a[2]])=min(8,3)=3,max(6,3)=6;
X=7,f[2][7]=min(f[1][7]+b[2],f[1][7-a[2]])=min(8,0)=0,max(7,3)=7;
完成第二件任务需要的最少时间是当X=5的时候,此时B执行第一件任务,A执行第二件任务,同时进行

当完成最后一件任务时,A的停机时间是j(即花费时间),B的停机时间是f[n][j],(就是A完成n件任务花费j时间的时候B停机的时间),要取最后停机的那个时间才是最后的时间就是最优解

算法复杂度分析

由于对于每个任务,需要遍历A所花的所有时间,设任务有n个,A花费时间总和为m,
计算f[i][j]花费的时间为常数级别,所以时间复杂度为O(nm),空间复杂度就是一个二维数组nm

代码

#include
#include
#define MAXN 1005
#include
#include
int a[MAXN];
int b[MAXN];

int f[MAXN][MAXN]; 
int n;

using namespace std;

int task_schedule(int *a,int *b,int n)
{
	int sumA=a[1];//k=1 只有一件任务的时候
	for(int x=0;x<a[1];x++)
	{
		f[1][x]=b[1];
	}
	f[1][a[1]]=a[1]<b[1]?0:b[1];
	//初始化
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<=n;j++)
		{
			f[i][j]=INT_MAX;//在A完成第i个任务的时间不超过j的情况下B完成任务的最短时间 
		}
	 } 
	 for(int k=2;k<=n;k++)
	 {
	 	sumA+=a[k];//遍历A的完成任务的时间

	 	for(int x=0;x<=sumA;x++)
	 	{
	 		if(x<a[k])//限定完成时间小于完成第k个任务的时间,只能由B执行第k个任务
	 		{
	 			f[k][x]=f[k-1][x]+b[k];
			  }
			else{//比较第k个任务由A完成和B完成B花费的最短时间
			  	f[k][x]=f[k-1][x]+b[k]<f[k-1][x-a[k]]?f[k-1][x]+b[k]:f[k-1][x-a[k]];
			  	
			  } 

		 }
	 }

	int min=INT_MAX;
	 for(int i=0;i<=sumA;i++)
	 {
	 	int temp=f[n][i]>i?f[n][i]:i;//选择完成最后一个任务时停机时间最晚的那个
	 	if(temp<min)
	 	{
	 		min=temp;//选择这么多个停机时间最晚里面的最短时间作为两台机器完成任务的最短时间
		 }
	 }
	 return min;
}
int main(){
	
	int n;
	ifstream in("input.txt");
	ofstream out("output.txt");
	in>>n;
	int *a=new int[n];//开辟n个int空间,让指针a指向起始地址
	int *b=new int[n];
	for(int i=1;i<=n;i++)
	{
		in>>a[i];
	
	 } 
	for(int i=1;i<=n;i++)
	{
		in>>b[i];
	
	 } 
	int min_time=task_schedule(a,b,n);
	out<<min_time<<endl;
	cout<<min_time<<endl;
	in.close();
	out.close();
} 

在看了很多博客之后自己总结出一个比较容易看懂的write up,可能对问题的认识还不是很深入,如果有错误或者高见,欢迎发邮件至[email protected] 指正和交流讨论!

你可能感兴趣的:(算法设计与分析,算法,动态规划)