Transcript Ch06-1

Ch.06
Branch-and-Bound (분기한정법)
(Ch.05-7 포함)
[CPA340] Algorithms and Practice
Youn-Hee Han
http://link.kut.ac.kr
Branch-and-Bound? – 특징
 분기한정법은 최적화문제를 해결하기위해 되추적 기술을
향상시킨 기법이다.
 되추적 기법과 유사하게 상태공간트리를 구축하여 해결
 분기한정법이 되추적 기법과 다른 점
 최적의 해를 구하는 문제(optimization problem)에만 적용
 Note: 최적의 해를 구하기 위해서는 궁극적으로 모든 해를 다 고려해 보
아야 한다. 즉, 분기 한정법은 가능한 모든 해를 모두 고려한 후에 답을
출력
 트리를 순회(traverse)하는 방법을 좀 더 효율적으로 택한다.
 Note: 되추적은 항상 깊이 우선 검색을 한다.
Page 2
Branch-and-Bound? – 원리
 각 노드를 방문할 때 마다, 그 노드가 유망한지의 여부를 결정
하기 위해서 한계치(bound)를 계산한다.
 한계치는 그 노드로부터 가지를 뻗어나가서(branch) 얻을 수 있는 해
답치의 한계를 나타낸다.
 한계치가 이전까지 찾은 최고 해답값보다 더 좋으면 그 마디는 유망하
다 (Promising).
 따라서 만약 그 한계치가 지금까지 찾은 최적의 해답치 보다
좋지 않은 경우는 더 이상 가지를 뻗어서 검색을 계속할 필요
가 없으므로, 그 노드는 유망하지 않다고 할 수 있다.
(이 경우, 해당 서브트리를 가지치기(pruning)한다.)
Page 3
0-1배낭 채우기 문제 (0-1 Knapsack Problem)(1/2)
문제의 개념적 정의
 어떤 도둑이 보석상에서 배낭을 매고 침입했다.
 훔칠 보석의 총 무게가 용량 W를 초과하면 배낭이 망가진다.
 도둑이 똑똑하여 각 보석의 “무게”와 “값어치”를 알고 있다.
 이 도둑은 총 무게가 W를 초과하지 않으면서 보석들의 총 값어치
가 최대가 되도록 보석을 배낭에 담고자 한다.
Page 4
0-1배낭 채우기 문제 (0-1 Knapsack Problem)(2/2)
문제의 정형적 정의
 입력:
• 보석 (item)의 개수: n, S = {item1, item2,…, itemn}
• wi = itemi의 무게, pi = itemi의 가치
• W = 배낭에 넣을 수 있는 총 무게
 문제 정의
item A wi  W 를 만족하면서 
i
itemi A
pi 가
최대가 되도록
A  S가 되는 A를 결정하는 문제이다.
Page 5
0-1 Knapsack – Depth-First-Search 개념
 이후 내용은 교재의 5.7절에 해당 (p. 212~221)
 깊이우선검색을 이용하는 분기한정 가지치기 (= 되추적 알고리즘)
(1/2)
• 상태공간트리를 구축하여 되추적 기법으로 문제를 푼다.
• 루트 노드에서 왼쪽으로 가면 첫번째 아이템을 배낭에 넣는 경우이고, 오른쪽
으로 가면 첫번째 아이템을 배낭에 넣지 않는 경우이다.
• 동일한 방법으로 트리의 수준 1에서 왼쪽으로 가면 두 번째 아이템을 배낭에
넣는 경우이고, 오른쪽으로 가면 그렇지 않는 경우이다.
Page 6
0-1 Knapsack – Depth-First-Search 개념
 깊이우선검색을 이용하는 분기한정 가지치기 (= 되추적 알고리즘)
(2/2)
• 이런 식으로 계속하여 상태공간트리를 구축하면, 루트 노드로부터 리프 노드
까지의 모든 경로는 해답후보가 된다.
• 이 문제는 최적의 해를 찾는 문제(optimization problem)이므로 검색이 완전
히 끝나기 전에는 해답을 알 수가 없다.
• 따라서 검색을 하는 과정 동안 항상 그 때까지 찾은 최적의 해를 기억해 두어
야(메모리에 저장해 두어야) 한다.
Page 7
0-1 Knapsack – DFS 기반 Generic Algorithm
void checknode(node v) {
node u;
if(value(v) is better than best)
best = value(v);
if(promising(v))
for(each child u of v)
checknode(u);
}
 best: 현재까지 찾은 제일 좋은 해답치
 value(v): 노드 v에서의 해답치
Page 8
0-1 Knapsack – DFS 기반 Algorithm Sketch (1/3)
 wi와 pi를 각각 i번째 아이템의 무게와 값어치라고 하면, pi/wi 의 값이 큰
것부터 내림차순으로 아이템을 정렬한다.
 다음 값들을 각 노드에 대해서 계산한다.
• profit: 그 노드에 오기까지 넣었던 아이템 값어치의 합.
• weight: 그 노드에 오기까지 넣었던 아이템 무게의 합.
• bound(향후 이익 한계치):  다음 페이지!
• maxprofit : 지금까지 찾은 최선의 해답이 주는 값어치
Page 9
0-1 Knapsack – DFS 기반 Algorithm Sketch (2/3)
• bound(향후 이익 한계치): 임의의 노드가 수준 i에 있다고 하고, 자손 노드 중
수준 k (k >i)에 있는 노드에서 총 무게가 W를 넘는다고 하자. 그러면, 다음과
같이 bound를 구할 수 있다.
i번째 아이템까지 고려했을 때의 무게와
i+1번째 부터 k-1 번째 아이템 까지의 무게의 합
totweight  weight 
k 1
wj

j i 1
k 1


p
bound   profit   p j   ( W  totweight )  k


wk
j i 1


빈틈없이 배낭 채우기
문제에서의 개념 사용
k 번째 아이템 을 부분적으로나마
넣을 수 있다고 가정할 때의 이익
k-1 번째 아이템 까지의 이익
[주의] Root 노드: 수준 0
Page 10
0-1 Knapsack – DFS 기반 Algorithm Sketch (3/3)
 초기값(루트 노드): maxprofit := $0; profit := $0; weight := 0
 깊이우선순위로 각 노드를 방문하여 다음을 수행한다:
1. 그 노드의 profit과 weight를 계산한다.
2. 그 노드의 bound를 계산한다.
3. 현재 노드의 profit이 maxprofit보다 크면 maxprofit 값을 갱신한다.
4. (weight < W) && (bound > maxprofit)이면, 유망하다고 보고 가지를 뻗
어(Branch)나간다.
(무게가 초과하지 않았고, 향후 가치가 최대 가치보다 클 수 있다면)
그렇지 않으면 유망하지 않다고 보고, 되추적(Backtraking)한다.
 상기 과정을 모든 노드를 방문할 때까지 수행한다.
 Note: 실제로는 임의의 노드에서 가지치기가 되므로, 모든 노드를 방문하지는 않음
 고찰: 현재까지 최적이라고 여겼던 노드로부터 계속 가지를 뻗어나아가
최적해가 항상 나온다는 보장은 없다.
Page 11
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (1/6)
 보기: n = 4, W = 16이고, 다음과 같은 아이템 내역을 가진다.
i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
$20
$6
$5
$2
 이때, 되추적을 사용하여 구축되는 가지치기가 이루어진 상태공간트리를
그려 보시오.  다음 페이지 그림 참조
Page 12
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (2/6)
W = 16
i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
profit
$20
$6
$5
$2
maxprofit = 0
weight
bound
maxprofit = 40
maxprofit = 90
maxprofit = 70
maxprofit = 80
maxprofit = 70
maxprofit = 90
maxprofit = 70
maxprofit = 90
maxprofit = 90
maxprofit = 80
maxprofit = 80
maxprofit = 90
Page 13
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (3/6)
 상태공간트리에서 검색하는 노드의 개수는 13이다.
totweight  weight 
 (0,0) 에서 bound 값 구하기
k 1
wj

j i 1
k 1


p
bound   profit   p j   ( W  totweight )  k


wk
j i 1


i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
$20
$6
$5
$2
Page 14
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (4/6)
totweight  weight 
k 1
 wj
j i 1
 (1,1) 에서 bound 값 구하기
k 1


p
bound   profit   p j   ( W  totweight )  k


wk
j i 1


i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
$20
$6
$5
$2
Page 15
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (5/6)
totweight  weight 
k 1
 wj
j i 1
 (2,1) 에서 bound 값 구하기
k 1


p
bound   profit   p j   ( W  totweight )  k


wk
j i 1


 k=3, i=2
 (3,1) 에서는 bound를 구할 필요가 없다.
i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
$20
$6
$5
$2
 Why? weight=17이 W=16을 초과하였으므로
Page 16
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (5/6)
totweight  weight 
k 1
 wj
j i 1
 (3,2) 에서 bound 값 구하기
k 1


p
bound   profit   p j   ( W  totweight )  k


wk
j i 1


i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
$20
$6
$5
$2
Page 17
0-1 Knapsack – DFS 기반 Algorithm 적용 예제 (6/6)
totweight  weight 
k 1
 wj
j i 1
k 1


p
bound   profit   p j   ( W  totweight )  k


wk
j i 1


i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
$20
$6
$5
$2
Page 18
0-1 Knapsack – DFS 기반 Algorithm 분석
 교재 5.7.2절 (p. 221-222)
 이 알고리즘이 점검하는 노드의 수에 대한 상한은 (2n)이다.
 이전 예제의 경우: 점검한 노드는 13개이다. 이 알고리즘이
DP 기반으로 설계한 알고리즘 ((2n))보다 좋은가?
• 확실하게 대답하기 불가능 하다.
• Horowitz와 Sahni(1978)는 Monte Carlo 기법을 사용하여 되추적 알
고리즘이 DP 기반 알고리즘 보다 일반적으로 더 빠르다는 것을 입증
하였다.
• Horowitz와 Sahni(1974)가 분할정복과 DP 기법을 적절히 조화하여
개발한 0-1 Knapsack 알고리즘은 (2n-1)의 시간복잡도를 가지는데,
이 알고리즘은 되추적 0-1 Knapsack 알고리즘 보다 일반적으로 빠르
다고 한다.
Page 19
0-1 Knapsack – DFS 기반 Algorithm 비판
 기존 DFS 기반 알고리즘은 분기한정의 특성을 제대로 활용하
고 있지 못하다.
 더 향상된 알고리즘에서 취할 수 있는 전략
 한계치(bound)를 계산하여 노드의 유망 여부를 검사할 수 있을 뿐만
아니라 유망한 노드의 한계치를 비교하여 가장 유망한 노드를 찾아
그 노드부터 검사
 이렇게 하는 것이 깊이 우선 방법으로 검색하는 것보다 효율적이다.
 이와같은 알고리즘을 분기 한정 가지치기 최고 우선 검색
(best-first search with branch-and-bound pruning)
이라 한다.
 이 가지치기는 너비 우선 검색을 수정하여 구현한다.
Page 20
Breadth-First-Search (1/2)
 너비우선검색(Breadth-First Search)순서:
(1) 루트 노드를 먼저 검색한다.
(2) 다음에 수준 1에 있는 모든 노드를 검색한다.
(왼쪽에서 오른쪽으로)
(3) 다음에 수준 2에 있는 모든 노드를 검색한다
(왼쪽에서 오른쪽으로)
(4) ...
Page 21
Breadth-First-Search (2/2)
 A Generic Algorithm for Breadth-First-Search
• 재귀(recursive) 알고리즘을 작성하기는 상당히 복잡하다.
• 따라서, 큐(queue)를 사용한다.
void breadth_first_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);
for(each child u of v) {
visit u;
enqueue(Q,u);
}
}
}
Page 22
BFS based Branch-and-Bound Algorithm
void breadth_first_branch_and_bound (state_space_tree T) {
queue_of_node Q;
node u, v;
number maxprofit;
initialize(Q);
// Q는 빈 대기열로 초기화
v = root of T;
// 루트 노드를 방문
enqueue(Q,v);
maxprofit = profit(v);
while(!empty(Q)) {
dequeue(Q,v);
for(each child u of v) { // 각 자식 노드를 방문
if(profit(u) > maxprofit && weight < W)
maxprofit = profit(u);
if(bound(u) > maxprofit && weight < W)
enqueue(Q,u);
}
}
}
Page 23
0-1 Knapsack – BFS 기반 상태공간트리
i
1
2
3
4
pi
$40
$30
$50
$10
wi
2
5
10
5
pi
wi
profit
$20
$6
$5
$2
weight
bound
mp = 40
mp = 40
mp = 70
mp = 70
mp = 70
mp = 70
mp = 90
mp = 70
mp = 70
mp = 90
mp = 90
mp = 90
totweight  weight 
mp = 90
k 1
 wj
j i 1
mp = 90
mp = 90
k 1


pk
mp = 90 bound   profit   p j   ( W  totweight ) 


wk
j i 1


Page 24
0-1 Knapsack – BFS 기반 큐
 Queue에서의 진행모습 (1/5)
Queue
maxprofit=0
(0,0)
$0,0
$115
maxprofit=40
(1,1)
$40,2
$115
(1,2)
$0,0
$82
(0,0)
$0,0
$115
maxprofit=70
(1,2)
$0,0
$82
(2,1)
$70,7
$115
(1,1)
$40,2
$115
(0,0)
$0,0
$115
(2,2)
$40,2
$98
Page 25
0-1 Knapsack – BFS 기반 큐
No!
(2,4)
$0,0
$60
No!
(3,1)
$120,17
$0
 Queue에서의 진행모습 (2/5)
maxprofit=70
maxprofit=70
(2,1)
$70,7
$115
(2,2)
$40,2
$98
(2,3)
$30,5
$82
(1,2)
$0,0
$82
(1,1)
$40,2
$115
(0,0)
$0,0
$115
(2,2)
$40,2
$98
(2,3)
$30,5
$82
(3,2)
$70,7
$80
(2,1)
$70,7
$115
(1,2)
$0,0
$82
(1,1)
$40,2
$115
Since $60 < $70 (best)
Since 17 > 16(=W)
(0,0)
$0,0
$115
Page 26
0-1 Knapsack – BFS 기반 큐
 Queue에서의 진행모습 (3/5)
No!
maxprofit=90
(2,3)
$30,5
$82
(3,2)
$70,7
$80
(3,3)
$90,12
$98
(2,2)
$40,2
$98
(2,1)
$70,7
$115
(1,2)
$0,0
$82
No!
maxprofit=90
(3,2)
$70,7
$80
(3,3)
$90,12
$98
(2,3)
$30,5
$82
(2,2)
$40,2
$98
(1,1)
$40,2
$115
(3,5)
$80,15
$82
(2,1)
$70,7
$115
(1,2)
$0,0
$82
(3,4)
$40,2
$50
Since $50 < $90 (best)
(0,0)
$0,0
$115
(3,6)
$30,5
$40
(1,1)
$40,2
$115
Since
$40 < $90 (best)
$82 < $90 (best)
(0,0)
$0,0
$115
Page 27
0-1 Knapsack – BFS 기반 큐
 Queue에서의 진행모습 (4/5)
No!
maxprofit=90
(4,1)
$80,12
$80
(4,2)
$70,7
$70
Since
$80 < $90 (best)
$70 < $90 (best)
(3,3)
$90,12
$98
(3,2)
$70,7
$80
(2,3)
$30,5
$82
(2,2)
$40,2
$98
(2,1)
$70,7
$115
(1,2)
$0,0
$82
(1,1)
$40,2
$115
(0,0)
$0,0
$115
Page 28
0-1 Knapsack – BFS 기반 큐
 Queue에서의 진행모습 (5/5)
No!
maxprofit(best)=90
(4,3)
(4,4)
$100,17 $90,12
$0
$90
Since
17 > 16(=W)
$90 = $90 (best)
Empty!
(3,3)
$90,12
$98
(3,2)
$70,7
$80
(2,3)
$30,5
$82
(2,2)
$40,2
$98
(2,1)
$70,7
$115
(1,2)
$0,0
$82
(1,1)
$40,2
$115
(0,0)
$0,0
$115
Page 29
0-1 Knapsack – BFS 기반 상태공간트리
 기존 DFS 방식과 다른 점
 되추적 기법을 실현하기 위한 재귀호출을 이용하지 않는다.

Note: 되추적 방법에서 재귀호출 자체가 스택(Activation Recods 스택)
을 활용하여 논리적으로 트리를 Traversal 하면서 되추적이 실현
(알고리즘 5.7 참조, p.219)
 BFS 방식에서는 논리적인 트리에 대한 Traversal을 위하여 Queue를
활용한 코딩을 할 필요가 있다.
(알고리즘 6.1 참조, p.233)
 분기한정 가지치기로 BFS를 하여 상태공간트리를 그려보면,
검색하는 노드의 개수는 17이다.
 되추적 알고리즘(DFS 기반 해결책-13개 노드 검색)보다 좋지 않다!
Page 30