• 沒有找到結果。

Branch-and-Bound

N/A
N/A
Protected

Academic year: 2021

Share "Branch-and-Bound"

Copied!
31
0
0

加載中.... (立即查看全文)

全文

(1)
(2)

2

Branch-and-Bound

作用

‧ 用來改良回溯演算法。

特點

‧ 使用狀態空間樹來解決問題。

‧ 不限制要怎麼走訪整棵樹。

( 回溯法有限制 )

‧ 只用來解決最佳化問題。

(3)

3

使用

Branch-and-Bound 修剪法之

最佳優先搜尋

‧ 除了使用 bound 值來決定一個節點是不是 promising 之外,

 還必須加以比較每個子節點的 bound 值,然後挑選具有

 最佳 bound 值的子節點進行走訪。

‧ 此方式通常會比事先決定的順序 ( 如 DFS) 更早到達代表

 最佳解的節點。這也是 BFS 的簡易修正版。

(4)

4

(5)

5

BFS Algorithm

void breadth_first_tree_search ( tree T ) { queue_of_node Q ; // 宣告一個先進先出的佇列 node u , v ; initialize ( Q ) ; // 初始時將佇列清空 v = root of T ; // 走訪根節點 visit v ; enqueue( Q, v ) ; // 將根節點存入佇列尾端 while ( ! empty ( Q ) ) { // 當佇列中有節點時 dequeue ( Q, v ) ; // 從佇列前端取出一個節點 v

for ( each child u of v ) {

visit u ; // 走訪 v 的每個子節點 u

enqueue ( Q , u ) ; // 每走訪一個子節點 u 就將它

} // 放到佇列中

} }

(6)

6 1 2 3 4 3 4 5 6 7 4 5 6 7 8 9 5 6 7 8 9 10 11 12 6 7 8 9 10 11 12 7 8 9 10 11 12 13 14 8 9 10 11 12 13 14 12 13 14 15 16 13 14 15 16 取出 1 取出 2 取出 3 取出 4 取出 5 取出 6 取出 7 取出 8~11 取出 12 取出 13~16 放入 1

BFS 演算法走訪樹的範例

(7)

7

n=4 , W=16

i

P

i

w

i

P

i

/w

i

1

$40

2

$20

2

$30

5

$6

3

$50

10

$5

4

$10

5

$2

將物品依照單位重量獲益比 (P

i

/ W

i

) 值由大到小排序。

狀態空間樹的每個節點內部有三個數字,由上而下為:

全部獲益 ( 即 profit )

全部重量 ( 即 weight )

獲益上限值 ( 即 bound )

Branch-and-Bound 以 BFS 走訪法來解 0-1 背包

問題

(8)

8

nonpromising 策略

(1) 由樹的根節點往下走到第 i 層節點時,若已經沒空間

再放入更多物品的話,則該節點就是 nonpromising 。

設 weight = 在第 i 層節點所累積的物品總重量

weight  W

則此節點一定是 nonpromising 。

背包載重限制

(9)

9

nonpromising 策略 ( 續 )

(2) 從貪婪法則的觀點來找出一個較不明顯的判斷 promising

與否的方法。

  

1 1 k i j j

w

weight

totweight

k k k i j j

w

P

totweight

W

p

profit

bound





   1 1 前 k-1 個物品的 總獲益 可以分配給 第 k 個物品 的容量 第 k 個物品 單位重量的 獲益 總重量 到第 i 層節點為止的總重量 第 i+1 層到 k-1 層節 點為止的總重量。 因為到第 k 層就爆了 。 第 i 層節點 的最大獲益 上限值。 第 1 到 i 層節點的總獲益值

(10)

10

branch-and-bound 以 BFS 走訪法產生的樹

目前最佳值 maxprofit = 0

40

40

70

70

70

70

70

70

90

90

90

90

90

90

90

90

profit weight bound

(11)

11

Breadth-first branch-and-bound Algorithm

void breadth_first_branch_and_bound ( state_space_tree T , number& best )

{ queue_of_node Q ; // 宣告一個佇列用來擺放欲走訪的節點 node u , v ; initialize ( Q ) ; // 啟始時將佇列清空 v = root of T ; enqueue ( Q , v ) ; // 走訪 root 節點,並將它加入佇列尾端 best = value ( v ) ; // 初始化目前最佳值 while ( ! empty ( Q ) ) { dequeue ( Q , v ) ; // 從佇列前端取出一個節點 v

for ( each child u of v ) { // 走訪 v 的每個子節點 u

if ( value ( u ) is better than best )

best = value ( u ) ; // 若找到更好的結果就更新目前最佳值

if ( bound( u ) is better than best )

enqueue( Q , u ) ; // 若一個節點是 promising 就把它加入佇列

} // 尾端,以待下一層走訪時使用

} }

(12)

12

演算法中的節點結構

struct node

{

int level ; // 該節點在樹中的層級

int profit ; // 目前累積的利益值

int weight ; // 目前累積的物品重量值

}

(13)

13

使用

Branch-and-bound 之廣度優先搜尋法來解決 0-1 背包問

問題:給定 n 個物件及其個別 weight 與 profit 值 ( 皆為正整數 ) 。

給定 W 值。在總重量不超過 W 的條件下,找出一組物件

使其總獲益是最大的。

輸入:正整數 n 和 W 。

陣列 w 與 p ( 索引均由 1 到 n ,且根據 p[i]/w[i] 由大到小

排序過 ) 。

輸出:正整數 maxprofit ( 即最大獲益 ) 。

本演算法只找出最大獲益值,若想要輸出被挑選的物品編號,可

以自行修改。

(14)

14

Algorithm ( 續 )

void knapsack2 ( int n , const int p[] , const int w[] , int W , int& maxprofit )

{ queue_of_node Q ; // 宣告一個要存放欲走訪節點的佇列

node u , v ;

initialize ( Q ) ; // 初始時將佇列清空

v.level = 0 ; v.profit = 0 ; v.weight = 0 ; // 將根節點初始化,並走訪它

maxprofit = 0 ; // 初始化目前最佳值

enqueue ( Q , v ) ; // 將根節點加入佇列尾端

while ( ! empty ( Q ) ) { // 只要佇列中還有節點未走訪,就一直做下去

dequeue ( Q , v ) ; // 從佇列前端取出欲走訪子節點的父節點

u.level = v.level + 1 ; // 將 u 設成 v 的下一層子節點其中之一

u.weight = v.weight + w[ u.level ] ; // 將 u 設成拿取下一層物品的子節點

u.profit = v.profit + p[ u.level ] ;

if ( u.weight <= W && u.profit > maxprofit ) // 若背包沒有爆掉,且獲

maxprofit = u.profit ; // 得利益值大於最佳值,則更新它

if ( bound ( u ) > maxprofit ) enqueue ( Q , u ) ; // 檢查 u 是否 promising

u.weight = v.weight ; u.profit = v.profit ; // 將 u 設成不拿取下一層物品

if ( bound ( u ) > maxprofit ) enqueue ( Q , u ) ; // 的子節點,並檢查它

} // 是否 promising

(15)

15

Algorithm ( 續 )

float bound ( node u ) // 回傳值就是 u 的 bound 值,呼叫者再把該值和目前最

{ index j , k ; // 佳值進行比較,以決定 u 是否為 promising

int totweight ; float result ;

if ( u.weight >= W ) return 0 ; // 背包爆掉則傳回 bound = 0

else {

result = u.profit ; // 先把 bound 值初設為到 u 節點為止的總共獲益值

j = u.level + 1 ;

totweight = u.weight ;

while ( j <= n && totweight + w[j] <= W ) {

totweight = totweight + w[j] ; // 盡可能多拿取一些物品

result = result + p[j] ; // 直到物品都拿光或是背包

j ++ ; // 爆掉為止

}

k = j ;

if ( k <= n ) result = result + (W-totweight)*(p[k]/w[k]) ; // 加上第 k 個

return result ; // 物品的部份利益

}

(16)

16

使用

Branch-and-bound 修剪法之

最佳

優先搜尋

下一頁

目前最佳值 maxprofit = 0

40

40

70

70

70

70

90

90

90

90

總共走訪了

11 個節點,

最佳值 =90

profit weight bound

上一頁

(17)

17

Best-first Branch-and-bound Algorithm

void best_first_branch_and_bound ( state_space_tree T , number& best ) { priority_queue_of_node PQ ; // 使用優先權佇列來存放欲走訪的節點 node u , v ; initialize ( PQ ) ; v = root of T ; // 先走訪根節點,並初設目前最佳值 best best = value ( v ) ; insert ( PQ , v ) ; // 將根節點插入優先權佇列中 while ( ! empty ( PQ ) ) { // 只要優先權佇列中還有未走訪節點就繼續做 remove ( PQ , v ) ; // 取出佇列中優先權 ( 即 bound) 最高的節點

if ( bound ( v ) is better than best ) // 若它仍然還是 promising 則往

for ( each child u of v ) { // 下層走訪它的每個子節點

if ( value ( u ) is better than best )

best = value ( u ) ; // 更新最佳值

if ( bound ( u ) is better than best )

insert ( PQ , u ) ; // 若 u 為 promising ,則將

} // 它插入佇列中

} }

(18)

18

使用

Branch-and-bound 並以最佳優先搜尋法

來解決

0-1 背包問題

狀態空間樹中的節點結構

struct node {

int level ; // 節點在樹中的層級

int profit ; // 到目前為止的總獲利值

int weight ; // 到目前為止的總重量值

float bound ; // 節點的最大獲利能力值

}

(19)

19

Algorithm ( 續 )

void knapsack3 ( int n , const int p[] , const int w[] , int W , int& maxprofit ) { priority_queue_of_node PQ ;

node u , v ;

initialize ( PQ ) ;

v.level = 0 ; v.profit = 0 ; v.weight = 0 ; maxprofit = 0 ;

v.bound = bound ( v ) ; // 走訪根節點,並將它加入優先權佇列中

insert ( PQ , v ) ;

while ( ! empty ( PQ , v ) ) {

remove ( PQ , v ) ; // 將 bound 值最高的節點取出來

if ( v.bound > maxprofit ) { // 如果它仍然是 promising 就往下層展開

u.level = v.level + 1 ;

u.weight = v.weight + w[ u.level ] ;

u.profit = v.profit + p[ u.level ] ; // 先走訪左子節點

if ( u.weight <= W && u.profit > maxprofit )

(20)

20

Algorithm ( 續 )

u.bound = bound ( u ) ;

if ( u.bound > maxprofit ) // 若左子節點 promising ,則加

insert ( PQ , u ) ; // 入優先權佇列中

u.weight = v.weight ;

u.profit = v.profit ; // 走訪右子節點

u.bound = bound ( u ) ;

if ( u.bound > maxprofit ) // 若右子節點 promising ,則加

insert ( PQ , u ) ; // 入優先權佇列中

} }

}

(21)

21 0 40 40 70 70 70 70 90 90 90 90 (0,0 ) (1,1 ) (1,2) (2,1 ) (2,2) (1,2) (2,2 ) (1,2) (3,2) (3,3 ) (1,2) (3,2) (1,2 ) (3,2) (3,2 ) 115 115 82 115 98 82 98 82 80 98 82 80 82 80 80

優先權佇列變化圖

(1,2) : 82 < 90 nonpromising (3,2) : 80 < 90 nonpromising (0,0) (1,2) (2,1) (2,2) (3,3)

(22)

22

售貨員旅行問題

                0 4 17 7 18 2 0 9 7 11 16 7 0 5 4 7 8 7 0 14 20 10 4 14 0

V

1

V

2

V

4

V

V

33

V

5 10 4 7 7 2

此相鄰矩陣代表了

所有頂點間皆有邊線

相連的圖

左圖的最佳旅程

若城市數目很多,且是高度連結的,那麼使用回溯法會產

生太多旅行路線。因此改用 branch-and-bound 。

(23)

23

(24)

24

計算狀態樹中每個節點的

bound

在這個問題中求的 bound 值是由該節點繼續往下層節點走訪

的可能最小路徑長度。只有 bound 值比目前最佳值還小,這

個節點才是 promising 。

在任意旅程中,從每個頂點離開時,應採用其發出之最短邊

線:

V

1

minimum ( 14, 4, 10, 20 ) = 4

V

2

minimum ( 14, 7, 8, 7 ) = 7

V

3

minimum ( 4, 5, 7, 16 ) = 4 => 4+7+4+2+4=21

V

4

minimum ( 11, 7, 9, 2 ) = 2 一個旅程的長度下限

V

5

minimum ( 18, 7, 17, 4 ) = 4 就是這些最小值的總

和,但不代表真有這

條路徑,可能不存在

(25)

25

計算狀態樹中每個節點的

bound 值

( 續 )

計算節點 [1,2] 的 bound 值:

V1 14 ( 已固定不能變動 )

V2 minimum ( 7 , 8 , 7 ) = 7

V3 minimum ( 4 , 7 , 16 ) = 4

V4 minimum ( 11 , 9 , 2 ) = 2

V5 minimum ( 18 , 7 , 17 , 4 ) = 4

                0 4 17 7 18 2 0 9 7 11 16 7 0 5 4 7 8 7 0 14 20 10 4 14 0

bound 值

= 14+7+4+2+4

= 31

(26)

26

計算節點 [1, 2, 3] 的 bound 值:

V

1

14 ( 已固定不能變動 )

V

2

7 ( 已固定不能變動 )

V

3

minimum ( 7 , 16 ) = 7

V

4

minimum ( 11 , 2 ) = 2

V

5

minimum ( 18 , 4 ) = 4

                0 4 17 7 18 2 0 9 7 11 16 7 0 5 4 7 8 7 0 14 20 10 4 14 0

bound 值

= 14+7+7+2+4

= 34

計算狀態樹中每個節點的

bound 值

( 續 )

(27)

27

狀態樹與

Bound 值

最佳解 = 無限大 37 31 31 31 31 31 31 30 30 5, 4

(28)

28

Algorithm 使用 Branch-and-bound 及最佳搜尋

法來解決售貨員旅行問題

狀態樹中的節點結構

struct node {

int level ;

// 節點在樹中的層級

ordered set path ;

// 到該節點為止的旅程路徑

number bound ;

// 該節點的旅程下限值

(29)

29

Algorithm ( 續 )

問題:在一有向權重圖中找出一條最佳旅程。 weight 必須為

非負整數。

輸入:一個有向權重圖 ( 以二維陣列 W 來表示,行列索引均

由 1 到 n , W[i][j] 代表由第 i 個頂點連到第 j 個頂點之

weight ) 。

該圖中的頂點數, n 。

輸出:變數 minlength ,其值為一條最佳旅程的長度。

變數 opttour ,其值為一條最佳旅程。

(30)

30

Algorithm ( 續 )

void travel2 ( int n , const number W[][] , ordered_set& opttour , number& minlength ) { priority_queue_of_node PQ ; node u , v ; initialize ( PQ ) ; v.level = 0 ; v.path = [1] ; // 令頂點 1 為起點 ( 即根節點 )

v.bound = bound( v ) ; // 計算根節點的 bound 值

minlength = 無限大 ; // 初始化最佳值

insert ( PQ , v ) ;

while ( ! empty ( PQ ) ) {

remove ( PQ , v ) ; // 取出下一個要展開的節點

if ( v.bound < minlength ) { // 如果它仍然是 promising

u.level = v.level + 1 ; // 開始計算它所有下一層節點

for ( all i such that 2 <= i <= n && i is not in v.path ) { u.path = v.path ;

(31)

31

Algorithm ( 續 )

if ( u.level == n - 2 ) { // 如果 u 在倒數兩層就直接處理

put index of only vertex not in u.path

at the end of u.path ; // 將最後一頂點加入路徑

put 1 at the end of u.path ; // 把頂點 1 加入

if ( length ( u ) < minlength ) { minlength = length ( u ) ; // 更新最佳值 opttour = u.path ; // 更新最佳路徑 } } else { // 還不到旅程的終點

u.bound = bound ( u ) ; // 計算 bound 值

if ( u.bound < minlength ) // 若 promising

insert ( PQ , u ) ; // 放入優先權佇列中

} }

} } }

參考文獻

相關文件

於是我們若想要在已知函數值的某一點,了解附近大概的函

對任意連續函數,每個小區間上的取樣點 x 都選擇在函數最 大值與最小值發生的點。如下圖,淺色方塊的高度都挑選小

Proposition 3.2.21 以及 Proposition 3.2.22, metric space 的 compact subset closed bounded.. least upper bound 以及 greatest lower

•  要使⽤用 Google Classroom, 學校必須先成功申請使⽤用 Google Apps for Education.. •  Google Classroom 並不是⼀一個全功能的 LMS,

觀察以上使用了幾個不同的起始點後,.

證明比較鬆的upper bound或lower bound來慢慢 接近tight

Convex optimization, compressed sensing, ℓ 1 -regularization, nuclear/trace norm, regression, variable selection, sensor network localization, approximation accuracy, proximal

值得一提的是,Add-in 在 Inventor 運行時會自動加載的特性是一個非常實用的功 能。使用者可以在執行 Inventor 前選擇所需要加載的 Add-in,而沒有選擇的