1、問題描述
設有n個獨立的作業{1, 2, …, n}, 由m臺相同的機器進行加工處理. 作業i所需時間爲t i. 約定:任何作業可以在任何一臺機器上加工處理, 但未完工前不允許中斷處理,任何作業不能拆分成更小的子作業。要求給出一種作業調度方案,使所給的n 個作業在儘可能短的時間內由m臺機器加工處理完成。
多機調度問題是一個NP完全問題,到目前爲止還沒有完全有效的解法。對於這類問題,用貪心選擇策略有時可以設計出一個比較好的近似算法。
2、貪心算法求解思路
採用最長處理時間作業優先的貪心策略:
當n≤m時, 只要將機器i的[0, ti]時間區間分配給作業i即可。
當n>m時, 將n個作業依其所需的處理時間從大到小排序,然後依次將作業分配給空閒的處理機。
具體代碼如下:
package 貪心;
//public class Greedy
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @author 葛帥帥
*/
public class Greedy {
public static class JobNode implements Comparable{
int id;//作業的標號
int time;//作業時間
public JobNode(int id,int time){
this.id=id;
this.time=time;
}
@Override
public int compareTo(Object x) {//按時間從大到小排列
int times=((JobNode)x).time;
if(time>times) return -1;
if(time==times) return 0;
return 1;
}
}
public static class MachineNode implements Comparable{
int id;//機器的標號
int avail;//機器空閒的時間(即機器做完某一項工作的時間)
public MachineNode(int id,int avail){
this.id=id;
this.avail=avail;
}
@Override
public int compareTo(Object o) {//升序排序,LinkedList的first爲最小的
int xs=((MachineNode)o).avail;
if(avail<xs) return -1;
if(avail==xs) return 0;
return 1;
}
}
public static int greedy(int[] a ,int m){
int n=a.length;//a的下標從1開始,所以n(作業的數目)=a.length-1
int sum=0;
if(n<=m){
for(int i=0;i<n;i++)
sum+=a[i+1];
System.out.println("爲每個作業分別分配一臺機器");
return sum;
}
List<JobNode> d=new ArrayList<JobNode>();//d保存所有的作業
for(int i=0;i<n;i++){//將所有的作業存入List中,每一項包含標號和時間
JobNode jb=new JobNode(i+1,a[i]);
d.add(jb);
}
Collections.sort(d);//對作業的List進行排序
LinkedList<MachineNode> h=new LinkedList<MachineNode>();//h保存所有的機器
for(int i=1;i<=m;i++){//將所有的機器存入LinkedList中
MachineNode x=new MachineNode(i,0);//初始時,每臺機器的空閒時間(完成上一個作業的時間)都爲0
h.add(x);
}
int test=h.size();
for(int i=0;i<n;i++){
Collections.sort(h);
MachineNode x=h.peek();
System.out.println("將機器"+x.id+"從"+x.avail+"到"+(x.avail+d.get(i).time)+"的時間段分配給作業"+d.get(i).id);
x.avail+=d.get(i).time;
sum=x.avail;
}
return sum;
}
public static void main(String[] args) {
int[] a={14,2,3,4,5,6,8,8,9};
// 1,2,3,4,5,6,7 ,8,9
int m=3;
int sum=greedy(a,m);
System.out.println("總時間爲:"+sum);
}
}
/**
運行結果:
將機器1從0到14的時間段分配給作業1
將機器2從0到9的時間段分配給作業9
將機器3從0到8的時間段分配給作業7
將機器3從8到16的時間段分配給作業8
將機器2從9到15的時間段分配給作業6
將機器1從14到19的時間段分配給作業5
將機器2從15到19的時間段分配給作業4
將機器3從16到19的時間段分配給作業3
將機器3從19到21的時間段分配給作業2
總時間爲:21
*/