演算法導論 15 1裝配線排程

2021-10-07 11:45:41 字數 4266 閱讀 2474

總共有n個裝配站;

底盤進入到裝配線1和裝配線2的時間記錄在二元陣列e[2]上;

底盤在裝配線1和裝配線2上每個站的時間記錄在陣列a1[n] 和a2[n]上;

底盤在每個站上換裝配線的時間記錄在t1[n-1], t2[n-2]上;(在最後乙個站時候, 不需要換裝配線了,所以陣列只有n-1個資料)

底盤離開裝配線的時間存放在二元陣列x[2]上面;

求得的最優解記錄在陣列f1[n] 和f2[n]上;

每次做出的選擇記錄在陣列l1[n-1], l2[n-1]上;(在最後乙個站的時候, 不需要做選擇了, 所以只有n-1個元素)

暴力法求解:

如果有n個裝配站, 每個裝配站都要考慮是選擇裝配線1還是裝配線2, 這樣時間複雜度就是2^n次方;

動態規劃演算法,子問題空間是一維的,每乙個子問題要兩次選擇,所以時間複雜度 = n *2;

動態規劃求解:

1) 步驟1(最優化結構分析)

將對裝配線1 和 裝配線2的求解區分開來;

對裝配線1而言,邊界是第乙個裝配站的解, f1[0] = e[0] + a1[0];

對第i個裝配站的解a(i), 可以由其子問題的解構成, 即只有乙個子問題a(i-1),即第i-1個解;(第i個問題的解是由第i-1個問題的解組成的。因此其子問題空間就是一維的;

對於每乙個子問題, 都有兩種選擇:選擇1 是選擇裝配站s(1, i-1); 選擇2 是選擇裝配站s(2, i-1);

因此,其時間複雜度 = 子問題空間 × 選擇次數 = n × 2 = 2n,

使用剪貼技術證明子問題的最優解構造了原問題的最優解:假設通過裝配站s(1, i)的最快路線通過了裝配站s(1, i-1), 那麼這個最快路線也是通過裝配站s(1, i-1)的最快路線;如果假設存在其他一條最快路線通過裝配站s(1, i-1), 那麼會導致通過裝配站s(1, i)的最快路線不是最快的,形參矛盾;

經過以上分析,可以得到乙個最優子結構乙個問題的最優解包含了子問題的最優解,這是引用動態規劃的標誌之一。 因此可以使用動態規劃演算法。

以上相同的分析適用於裝配線2;

2) 步驟2 (乙個遞迴的解)

依據最優子結構, 乙個問題的最優解包含有子問題的最優解, 因此可以利用子問題的最優解來遞迴得到原問題的最優解;

最終的目標是求得底盤通過裝配線的最短時間, 即f*;

f* = min(f1[n] + x[0], f2[n] +x[1]);

因此需要求得f1[n] 和f2[n];

對於邊界: f1[0] = e[0] + a1[0]; f2[0] = e[1] + a2[0];

對於第i個裝配站: f1[i] = min(f1[i-1] + a1[i], f2[i-1] + t2[i-1] + a1[i]) , 使用min函式做出選擇

3) 步驟3(計算最快時間)

如果根據上面的遞迴式子使用自頂向下遞迴演算法編碼,其時間複雜度是z^n;

考慮計算f(i, j)的次數, 計算f(1, n)一次, 要計算f(1, n-1)2次,計算f(1, n-2) 4次,計算f(1, 1) 2^(n-1)次;

自頂向下的遞迴演算法實現如下:

void

fastest_way_recur_help

(int

* e,

int* x,

int* a1,

int* a2,

int* t1,

int* t2,

int*value1,

int*value2,

int n)

else

}int

fastest_way_recur

(int

* e,

int* x,

int* a1,

int* a2,

int* t1,

int* t2,

int n)

注意到f(i, j)的每乙個值僅僅依賴於f(1, i-1) 和f(2, i-1), 可以使用自底向上的動態規劃演算法:

自底向上的動態規劃**如下:

int

fastest_way

(int

* e,

int* x,

int* a1,

int* a2,

int* t1,

int* t2,

int* f1,

int* f2,

int* l1,

int* l2,

int n,

int* value)

else

//對於裝配線2

if(f2[i -1]

<

(f1[i -1]

+ t1[i -1]

))else

}//加上離開裝配線的時間後進行比較if(

(f1[n -1]

+ x[0]

)<

(f2[n -1]

+ x[1]

))else

}

4) 步驟4(構造通過工廠最快的線

遞迴實現列印路徑**如下:

void

print_station_recur

(int

* l1,

int* l2,

int way,

int n)

非遞迴實現列印路徑**如下:

void

print_station

(int

* l1,

int* l2,

int way,

int n)

}

int

main()

;int x[2]

=;int t1[5]

=;int t2[5]

=;int a1[6]

=;int a2[6]

=;int value;

int* l1 =

(int*)

malloc

((n -1)

*sizeof

(int))

;int

* l2 =

(int*)

malloc

((n -1)

*sizeof

(int))

;int

* f1 =

(int*)

malloc

(n *

sizeof

(int))

;int

* f2 =

(int*)

malloc

(n *

sizeof

(int))

;int way =

fastest_way

(e, x, a1, a2, t1, t2, f1, f2, l1, l2, n,

&value)

;print_station

(l1, l2, way, n)

;printf

("value:%d\n"

, value)

;int result =

fastest_way_recur

(e, x, a1, a2, t1, t2, n)

;printf

("result: %d\n"

, result)

;return0;

}

15.1.1 修改程式print_station, 以站號遞增順序列印。

void

print_station_incre_recur

(int

* l1,

int* l2,

int way,

int n)

《演算法導論》筆記 第15章 15 1 裝配線排程

其實dp這一章可以跳過去的。不過經典問題還是有必要研究一下。15.1 1 說明應如何修改程式print stations,讓它以站號的遞增順序輸出各裝配站。若達到起點則輸出起點,否則遞迴向前。遞迴結束時輸出自身。15.1 2 利用替換法證明 在遞迴演算法中引用fi j 的次數ri j 等於2 n j...

演算法導論 動態規劃 裝配線排程

動態規劃 dynamic programming 是通過組合子問題的解而解決整個問題的。分治演算法是指將問題劃分為一些獨立的子問題,遞迴地求解各子問題,然後合併子問題的解而得到原問題的解。動態規劃適用於子問題不是獨立的情況,也就是各子問題包含公共的子子問題。在這種情況下,若用分治法則會做許多不必要的...

裝配線排程

問題描述 汽車生產工廠共有兩條裝配線,每條有n個裝配站 裝配線i 的第j 個裝配站表示為si,j,在該站的裝配時間為ai,j。乙個汽車底盤進入工廠,然後進入裝配線i i 為1或2 花費時間為ei。在通過一條線的第j 個裝配站後,這個底盤來到任一條線的第 j 1 個裝配站。如果它留在相同的裝配線,則沒...