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

以前講過一個類似的問題流水做業調度問題,那一道題最開始用動態規劃,推到最後獲得了一個Johnson法則,變成了一個排序問題,有興趣的能夠看一下http://www.javashuo.com/article/p-xjlqyjke-ep.htmlhtml

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

1、問題描述

給定n個做業的集合{J1,J2,…,Jn}。每一個做業必須先由機器1處理,而後由機器2處理。做業Ji須要機器j的處理時間爲tji。對於一個肯定的做業調度,設Fji是做業i在機器j上完成處理的時間。全部做業在機器2上完成處理的時間和稱爲該做業調度的完成時間和。批處理做業調度問題要求對於給定的n個做業,制定最佳做業調度方案,使其完成時間和達到最小。數組


 例:設n=3,考慮如下實例:
函數

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

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

做業1在機器1上完成的時間是2,在機器2上完成的時間是3設計

做業2在機器1上完成的時間是5,在機器2上完成的時間是63d

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

因此,做業調度的完成時間和= 3 + 6 + 10htm

這裏咱們能夠思考一下做業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]

2、算法設計

 


類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]的賦值函數

3、算法的效率

相關文章
相關標籤/搜索