多机调度问题(贪心算法)
问题:
设有n个独立的作业{1, 2, …, n},由m台相同的机器{M1, M2, …, Mm}进行加工处理,作业i所需的处理时间为ti(1≤i≤n),每个作业均可在任何一台机器上加工处理,但不可间断、拆分。多机调度问题要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。
思想:
贪心法求解多机调度问题的贪心策略是最长处理时间作业优先,即把处理时间最长的作业分配给最先空闲的机器,这样可以保证处理时间长的作业优先处理,从而在整体上获得尽可能短的处理时间。按照最长处理时间作业优先的贪心策略,当m≥n时,只要将机器i的[0, ti)时间区间分配给作业i即可;当m<n时,首先将n个作业依其所需的处理时间从大到小排序,然后依此顺序将作业分配给空闲的处理机。
代码:
package 贪心法解决多机调度问题;
import java.util.Arrays;
import java.util.Scanner;
public class HomeworkTest {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner scanner=new Scanner(System.in);
int M;//机器的数量
int N;//作业的数量
System.out.print("机器的数量:");
M=scanner.nextInt();
//machine(机器)
int machines[]=new int[M];//机器的编号
for(int i=0;i<machines.length;i++) {//为机器编号
machines[i]=i+1;
}
System.out.print("机器的编号为:");
System.out.println(Arrays.toString(machines));
System.out.print("作业的数量:");
N=scanner.nextInt();
int id[]=new int[N];//作业的编号
for(int i=0;i<id.length;i++) {//为作业编号
id[i]=i+1;
}
System.out.print("作业的编号为:");
System.out.println(Arrays.toString(id));
int time[]=new int[N];//N作业的处理时间
System.out.print("请输入作业的时间:");
for(int i=0;i<time.length;i++) {
time[i]=scanner.nextInt();
}
System.out.println("作业的时间为:");
for(int i=0;i<time.length;i++) {
System.out.print("作业 "+id[i]+" 的时间为 :"+time[i]+" ");
if((i+1)%3==0)
System.out.println();
}
System.out.println("****************");
GreedyHomework.greedyhomework(time, id, machines, M, N);
}
}
上面为测试方法,以3个机器,6个作业,作业的时间量为34,22,67,51,10,90.
具体算法如下:
package 贪心法解决多机调度问题;
import java.util.Arrays;
public class GreedyHomework {
/**
*
* @param time 处理作业的时间数组
* @param id 作业的编号数组
* @param machines 机器的编号数组
* @param M 机器的数量
* @param N 作业的数量
*/
public static void greedyhomework(int time[],int id[],int machines[],int M,int N) {
//用冒泡排序将作业的时间和编号按时间的降序重新排序
for(int i=0;i<time.length-1;i++) {
for(int j=i+1;j<time.length;j++) {
int temp=0;
if(time[i]<time[j]) {
temp=time[i];
time[i]=time[j];
time[j]=temp;
temp=id[i];
id[i]=id[j];
id[j]=temp;
}
}
}
//输出重新排序后的作业的时间数组和编号数组
System.out.println(Arrays.toString(time));
System.out.println(Arrays.toString(id));
System.out.println("****************");
int alltime[]=new int[M];//每台机器工作的时间总和
int plan[]=new int[N];//机器的分配的作业数和时间
//首先将M个作业分配个M个机器,若作业数小于等于机器数,此步完成则结束
for(int i=0;i<M;i++) {
alltime[i]=time[i];
plan[i]=alltime[i];
System.out.println("机器"+(i+1)+"从0到"+alltime[i]+"的时间分给作业"+(i+1));
}
//作业数大于机器数执行此步骤
for(int i=M;i<N;i++) {
int j=min(alltime); //将最先空闲的机器的下标赋给j
plan[j]=alltime[j]+time[i];//将机器[j+1]的时间更新,获得机器赋予那个作业的时间段
System.out.println("机器"+(j+1)+"从"+alltime[j]+"到"+plan[j]+"的时间分给作业"+(i+1));
alltime[j]+=time[i];//将机器alltime[j]更新
}
for(int i=0;i<M;i++) {
System.out.println("机器"+(i+1)+"的工作总时间为:"+alltime[i]);
}
System.out.println("****************");
int max=Max(alltime);
System.out.println("最短的工作时间为:"+max);
}
//返回时间最小的下标
public static int min(int arr[]) {
int min=(arr[0]<arr[1])?0:1;
min=(arr[min]<arr[2])?min:2;
return min;
}
//返回时间最大的值
public static int Max(int arr[]) {
Arrays.sort(arr);
return arr[arr.length-1];
}
}
测试结果为:
总结:
此算法存在不足,以上例子的机器数只能是三个,如果机器数有改变,则需要修改
//返回时间最小的下标
public static int min(int arr[]) {
int min=(arr[0]<arr[1])?0:1;
min=(arr[min]<arr[2])?min:2;
return min;
}
,如果机器数过大,此方法就会代码量冗余,可通过递归修改。
欢迎大家指出不足,一起进步,谢谢大家。