一、 問題描述
給定 n 個作業的集合 j = {j1, j2, …, jn}。每一個作業 j[i] 都有兩項任務分別在兩台機器上完成。每一個作業必須先由機器1 處理,然后由機器2處理。作業 j[i] 需要機器 j 的處理時間為 t[j][i] ,其中i = 1, 2, …, n, j = 1, 2。對於一個確定的作業 調度,設F[j][i]是作業 i 在機器 j 上的完成處理的時間。所有作 業在機器2上完成處理的時間之和 f = sigma F[2][i] 稱為該作業 調度的完成時間之和。
批處理作業調度問題要求對於給定的 n 個作業,制定最佳作業調度 方案,使其完成時間和達到最小。
二、 解題思路及所選算法策略的可行性分析
用優先隊列式分支限界法解決此問題。由於要從n個作業的所有排列中找出有最小完成時間和的作業調度,所以批處理作業調度問題的解空間樹是一顆排列樹。對於批處理作業調度問題,可以證明存在最佳作業調度使得在機器1和機器2上作業以相同次序完成(因為每個作業必須先在機器1上完成作業才能在機器2上進行作業)。
如果對於未安排的作業,對於其中一個作業,每當該作業在機器1上完成處理后都能立即在機器2上開始處理,則機器1沒有空閑時間,達到滿工作狀態,將此情況的未安排作業在機器2上的工作時間總和記為S1,同理將機器2滿工作狀態的情況下的工作時間總和記為S2,則必有:
所有作業機器2上完工時間和 >= 已安排作業機器2上完工時間和 + max{S1,S2}
其中當未安排作業按照在機器1、2上工作時間非遞減順序進行調度時,S1和S2同時取得極小值且和調度無關,由此可作為分支限界法中的限界函數。
偽代碼描述及復雜度分析
bbFlow(){
對各作業在機器1和2上作旭時間排序
do{
if(到達葉結點){
if(當前作業安排機器2上完成時間和 < bestc){
更新bestc;
更新最優解;
}
}else{
For(int i=enode.已安排作業數; i<總作業數; i++){
求得當前下屆bb;
If(bb < bestc){
結點插入最小堆;
}
}
}
取下一個拓展結點;
}while(enode!=null&&enode.s<=n)
}
三、 代碼實現
package 分支限界法; public class Nodes implements Comparable { int s;//已安排作業數 int sf2;//當前機器2上的完成時間和 int bb;//當前完成時間和下界 int[] f;//f[1]機器1上最后完成時間,f[2]機器2上最后完成時間 int[] x;//當前作業調度 public Nodes(int n){ //最小堆結點初始化 x=new int[n]; for(int i=0;i<n;i++) x[i]=i; s=0; f=new int[3]; f[1]=0; f[2]=0; sf2=0; bb=0; } public Nodes(Nodes e,int[] ef,int ebb,int n){ //最小堆新結點 x=new int[n]; for(int i=0;i<n;i++) x[i]=e.x[i]; f=ef; sf2=e.sf2+f[2]; bb=ebb; s=e.s+1; } @Override public int compareTo(Object o) { int xbb=((Nodes) o).bb; if(bb<xbb) return -1; if(bb==xbb) return 0; return 1; } } public class BBFlow { public int n;//作業數 public int bestc;//最小完成時間和 public int [][]m;//n個作業所需的處理時間數組 public int [][]b;//n個作業所需的處理時間排序數組 public int[][] a;//數組m和b的對應關系數組 public int[] bestx;//最優解 public boolean[][] y;//工作數組 public BBFlow(int n,int[][] m){ this.n=n; bestc=10000; this.m=m; b=new int[n][2]; a=new int[n][2]; bestx=new int[n]; y=new boolean[n][2]; } public void swap(int[][] b,int i,int j,int k,int t){ int temp=b[i][j]; b[i][j]=b[k][t]; b[k][t]=temp; } public void swap(int[] x,int i,int j){ int temp=x[i]; x[i]=x[j]; x[j]=temp; } /** * 對n個作業在機器1和2上所需時間排序 */ public void sort(){ int[] c=new int[n]; for(int j=0;j<2;j++){ for(int i=0;i<n;i++){ b[i][j]=m[i][j]; c[i]=i; } for(int i=0;i<n-1;i++){ for(int k=n-1;k>i;k--){ if(b[k][j]<b[k-1][j]){ swap(b,k,j,k-1,j); swap(c,k,k-1); } } } for(int i=0;i<n;i++) a[c[i]][j]=i; } } /** * 計算完成時間和下界 * @param enode * @param f * @return */ public int bound(Nodes enode,int[] f){ for(int k=0;k<n;k++){ for(int j=0;j<2;j++){ y[k][j]=false; } } for(int k=0;k<enode.s;k++){ for(int j=0;j<2;j++){ y[a[enode.x[k]][j]][j]=true; } } f[1]=enode.f[1]+m[enode.x[enode.s]][0]; f[2]=((f[1]>enode.f[2])?f[1]:enode.f[2])+m[enode.x[enode.s]][1]; int sf2=enode.sf2+f[2]; int s1=0; int s2=0; int k1=n-enode.s; int k2=n-enode.s; int f3=f[2]; //計算s1的值 for(int j=0;j<n;j++){ if(!y[j][0]){ k1--; if(k1==n-enode.s-1) f3=(f[2]>f[1]+b[j][0])?f[2]:f[1]+b[j][0]; s1+=f[1]+k1*b[j][0]; } } //計算s2的值 for(int j=0;j<n;j++){ if(!y[j][1]){ k2--; s1+=b[j][1]; s2+=f3+k2*b[j][1]; } } //返回完成時間和下界 return sf2+((s1>s2)?s1:s2); } /** * 優先隊列式分支限界法解批處理作業調度問題 * @param nn * @return */ public int bbFlow(int nn){ n=nn; sort();//對n個作業在機器1和2上所需時間排序 LinkedList<Nodes> heap=new LinkedList<Nodes>(); Nodes enode =new Nodes(n); //搜索排列空間樹 do{ if(enode.s==n){ //葉節點 if(enode.sf2<bestc){ bestc=enode.sf2; for(int i=0;i<n;i++){ bestx[i]=enode.x[i]; } } }else{ //產生當前擴展結點的兒子結點 for(int i=enode.s;i<n;i++){ swap(enode.x,enode.s,i); int[] f=new int[3]; int bb=bound(enode,f); if(bb<bestc){ //子樹可能含有最優解 //結點插入最小堆 Nodes node=new Nodes(enode,f,bb,n); heap.add(node); Collections.sort(heap); } swap(enode.x,enode.s,i); }//完成結點擴展 } //取下一個擴展結點 enode=heap.poll(); }while(enode!=null&&enode.s<=n); return bestc; } public static void main(String[] args) { int n=3; int[][] m={{2,1},{3,1},{2,3}};//m的下標從0開始 BBFlow f=new BBFlow(n,m); f.bbFlow(n); System.out.println("最優批處理作業調度順序為:"); for(int i=0;i<n;i++) System.out.print((f.bestx[i]+1)+" "); System.out.println(); System.out.println("最優調度所需的最短時間為:"+f.bestc); } } /************************* *運行結果 *最優批處理作業調度順序為: *1 3 2 *最優調度所需的最短時間為:18 *************************/