回溯法——批處理作業調度


問題描述
    給定 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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章