算法設計與分析——批處理作業調度(回溯法)


之前講過一個相似的問題流水作業調度問題,那一道題最開始用動態規划,推到最后得到了一個Johnson法則,變成了一個排序問題,有興趣的可以看一下https://www.cnblogs.com/wkfvawl/p/11667092.html

本篇博客主要參考自https://blog.csdn.net/qq_40685275/article/details/80403976

一、問題描述

給定n個作業的集合{J1,J2,…,Jn}。每個作業必須先由機器1處理,然后由機器2處理。作業Ji需要機器j的處理時間為tji。對於一個確定的作業調度,設Fji是作業i在機器j上完成處理的時間。所有作業在機器2上完成處理的時間和稱為該作業調度的完成時間和。批處理作業調度問題要求對於給定的n個作業,制定最佳作業調度方案,使其完成時間和達到最小。


 例:設n=3,考慮以下實例:

 看到這里可能會對這些完成時間和是怎么計算出來的會有疑問,這里我拿123和312的方案來說明一下。

 對於調度方案(1,2,3)

作業1在機器1上完成的時間是2,在機器2上完成的時間是3

作業2在機器1上完成的時間是5,在機器2上完成的時間是6

作業3在機器1上完成的時間是7,在機器2上完成的時間是10

所以,作業調度的完成時間和= 3 + 6 + 10

這里我們可以思考一下作業i在機器2上完成的時間應該怎么去求?

作業i在機器1上完成的時間是連續的,所以是直接累加就可以。但對於機器2就會產生兩種情況,這兩種情況其實就是上圖的兩種情況,對於(1,2,3)的調度方案,在求作業2在機器2上完成的時間時,由於作業2在機器1上還沒有完成,這就需要先等待機器1處理完;而對於(3,1,2)的調度方案,在求作業2在機器2上完成的時間時,作業2在機器1早已完成,無需等待,直接在作業1被機器1處理之后就能接着被處理。

綜上,我們可以得到如下表達式

if (F2[i-1] > F1[i])
F2[i] = F2[i-1] + t[2][i]
else
F2[i] = F1[i] + t[2][i]

二、算法設計

 


類Flowshop的數據成員記錄解空間的結點信息,M輸入作業時間,bestf記錄當前最小完成時間和,數組bestx記錄相應的當前最佳作業調度。

數組x[i],bestx[i],二維數組m[j][i];
數組x記錄當前調度;
bestx記錄當前最優調度;
初始時,x[i]=i ;      bestx[i]=∞;     (i=0,1,......,n)
二維數組m記錄各作業分別在兩台機器上的處理時間;
m[j][i]表示在第i台機器上作業j的處理時間

變量f1,f2,cf,bestf;
f1記錄作業在第一台機器上的完成時間;
f2記錄作業在第一台機器上的完成時間;
cf記錄當前在第二台機器上的完成時間和;
bestf記錄當前最優調度的完成時間和;

在遞歸函數Backtrack中,
當i>n時,算法搜索至葉子結點,得到一個新的作業調度方案。此時算法適時更新當前最優值和相應的當前最佳調度。
當i<=n時,當前擴展結點在i層,以深度優先方式,遞歸的對相應子樹進行搜索,對不滿足上界約束的結點,則剪去相應的子樹。

 

這里注意一下該程序的輸入,要現將機器1對應所有作業的處理時間輸入,再輸入機器2的,對應上面的例子的數據就是 232113

#include <stdio.h>
int x[100],bestx[100],m[100][100];//m[j][i]表示在第i台機器上作業j的處理時間
//數組bestx記錄相應的當前最佳作業調度。
int f1=0,f2,cf=0,bestf=10000,n;  //bestf記錄當前最小完成時間和
void swap(int *x,int t,int j)
{
    int temp = x[t];
    x[t] = x[j];
    x[j] = temp;
}

void Backtrack(int t)
{
    int tempf,j,i;
    if(t>n) //到達葉子結點,搜索到最底部
    {
        for( i=1; i<=n; i++)
        {
            bestx[i]=x[i];
        }
        bestf=cf;

    }
    else    //非葉子結點
    {
        for(j=t; j<=n; j++)
        {
            f1+=m[x[j]][1];  //記錄作業在第一台機器上的完成處理時間
            tempf=f2;//保存上一個作業在機器2的完成處理時間
            f2=(f1>f2?f1:f2)+m[x[j]][2];//保存當前作業在機器2的完成時間
            cf+=f2;               //cf記錄當前在機器2上的完成時間和
            if(cf<bestf)
            {
                swap(x,t,j);  //交換兩個作業的位置
                Backtrack(t+1);
                swap(x,t,j);
            }
            f1-=m[x[j]][1];
            cf-=f2;
            f2=tempf;
        }
    }
}


int main()
{
    int i,j;

    printf("請輸入作業數量\n");
    scanf("%d",&n);
    printf("請輸入在各機器上的處理時間\n");
    for(i=1; i<=2; i++)
    {
        for(j=1; j<=n; j++)
        {
            scanf("%d",&m[j][i]);
        }
    }
    for(i=1; i<=n; i++)
    {
        x[i]=i;  //記錄當前調度
    }
    Backtrack(1);

    printf("調度作業順序\n");
    for(i=1; i<=n; i++)
    {
        printf("%d\t",bestx[i]);
    }
    printf("\n");
    printf("處理時間:\n");
    printf("%d\n",bestf);
    return 0;
}

 注意swap函數,交換兩個作業的位置相當於重新賦值了,所以該程序沒有對x[i]的賦值函數

三、算法的效率

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM