問題描述
給定 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 個作業,制定最佳作業調度 方案,使其完成時間和達到最小。
tji 機器1 機器2
作業1 2 1
作業2 3 1
作業3 2 3
這3個作業的6種可能的調度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;
它們所相應的完成時間和分別是19,18,20,21,19,19。易見,最佳調度方案是1,3,2,其完成時間和爲18。
以1,2,3爲例:
作業1在機器1上完成的時間爲2,在機器2上完成的時間爲3
作業2在機器1上完成的時間爲5,在機器2上完成的時間爲6
作業3在機器1上完成的時間爲7,在機器2上完成的時間爲10
3+6+10=19,所以是19
1,3,2
作業1在機器1上完成的時間爲2, 在機器2上完成的時間爲3
作業3在機器1上完成的時間爲4,在機器2上完成的時間爲7
作業2在機器1上完成的時間爲7,在機器2上完成的時間爲8
3+7+8=18,所以時間和爲18
分析:
批處理作業調度是要從 n 個作業的所有排列中找出有最小完成時間和的作業調度,所以批處理調度問題的解空間是一棵排列樹。按照回溯法搜索排列樹的算法框架,設開始時x = [1, .., n]是所給的 n 個 作業,則相應的排列樹由所有排列構成。
代碼實現:
1. Java實現
import java.util.*;
public class FlowShop
{
static int n; //作業數
static int f1; //機器1完成處理時間
static int f; //完成時間和
static int bestf; //當前最優值
static int[][] m; //各作業所需要的處理時間
static int[] x; //當前作業調度
static int[] bestx; //當前最優作業調度
static int[] f2; //機器2完成處理時間
public static void trackback(int i) {
//i用來指示到達的層數(第幾步,從0開始),同時也指示當前執行完第幾個任務
if (i == n) { //得出一組最優值
for (int j = 0; j < n; j++) {
bestx[j] = x[j];
}
bestf = f;
}
else {
for (int j = i; j < n; j++) { //j用來指示選擇了哪個任務(也就是執行順序) tb(0)進來了,不管怎麼遞歸,就有j=0,1,2這三個過程,因此肯定能遍歷完全
f1 += m[x[j]][0]; //選擇第x[j]個任務來執行
if (i > 0) { //選擇出的不是第一個任務
f2[i] = ((f2[i - 1] > f1) ? f2[i - 1] : f1) + m[x[j]][1]; //從f2[i - 1] 和 f1中選一個大的出來
}
else {//選擇出的是第一個任務
f2[i] = f1 + m[x[j]][1];
}
f += f2[i];
if (f < bestf) {
swap(x, i, j); //關鍵:把選擇出的任務j調到當前執行的位置i
trackback(i + 1); //選擇下一個任務執行
swap(x, i, j); //遞歸後恢復原樣
}
f1 -= m[x[j]][0]; //遞歸後恢復原樣
f -= f2[i];
}
}
}
private static void swap(int[] x, int i, int j) {
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
private static void test() {
n = 3;
int[][] testm = {{2, 1}, {3, 1}, {2, 3}};
m = testm;
int[] testx = {0, 1, 2};
x = testx;
bestx = new int[n];
f2 = new int[n];
f1 = 0;
f = 0;
bestf = Integer.MAX_VALUE;
trackback(0); //起點可變用trackback(0),如果從一定點開始,就要用trackback(1)
System.out.println(Arrays.toString(bestx));
System.out.println(bestf);
}
public static void main(String[] args)
{
test();
System.out.println("Hello World!");
}
}
2.C++實現
#include<stdio.h>
#include<string.h>
#define N 3//作業數目
#define MAX 1000
int x[N+1]={0,1,2,3};
int m[3][N+1]={
0,0,0,0,
0,2,3,2,
0,1,1,3
};
int bestx[N+1];//用於保存結果調度順序
int f2[N+1];//第i階段機器2完成處理的時間
int f1=0;//機器1完成處理時間
int f=0;//當前完成時間和
int bestf=MAX;
void swap(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
}
void Backtrace(int t)
{
if(t>N)
{
bestf=f;
for(int i=1;i<=N;i++)
{
bestx[i]=x[i];
}
}
else
{
for(int i=t;i<=N;i++)
{
f1+=m[1][x[i]];
f2[t]=(f2[t-1]>f1?f2[t-1]:f1)+m[2][x[i]];
f+=f2[t];
swap(x[t],x[i]);
if(f<bestf)
{
Backtrace(t+1);
}
swap(x[t],x[i]);
f1-=m[1][x[i]];
f-=f2[t];
}
}
}
int main()
{
memset(bestx,0,(N+1)*sizeof(int));
memset(f2,0,(N+1)*sizeof(int));
Backtrace(1);
printf("該作業調度的最優完成時間和爲:%d\n調度順序爲:\n",bestf);
for(int i=1;i<=N;i++)
{
printf("%d ",bestx[i]);
}
return 0;
}
來源:http://blog.sina.com.cn/s/blog_690e57390100kf3p.html