아무튼 공부중/algorithm

[알고리즘] Branch and Bound Algorithm | 분기 한정법

멍정 2023. 12. 11. 16:23

Branch and Bound Algorithm

- backtracking을 개선한 알고리즘

- state space tree은 backtracking처럼 그대로 사용됨

- 최적화 문제에 사용

What is a bound?

: 바운드는 노드를 넘어 확장하여 얻을 수 있는 해의 값?

- 노드의 경계를 계산하여 노드가 유망한지 여부를 확인

- 경계값이 지금까지 발견된 최상의 솔루션의 값보다 크지 않으면 non-promising

=> k - 1까지의 가장 큰 값이 bound라서 다음 노드의 bound가 Maxprofit보다 작으면 확인 할 필요 없음!

-> 내가 찾은 값이 더 크니까!

The 0/1 Knapsack Problem Revisited

: 가방에 최대한 많은 물건을 훔치자!-> 얼마짜리를 몇키로까지 훔칠 수 있는가 -> 가격과 무게를 고려

 

- profit : 지금까지 내가 고른 노드들의 총 값(가격)- weight : 지금까지 고른 노드들의 총 무게(무게)- total weight(totweight) : 넘치기 일보 직전의 weight 값

 

-> k에서 weight값이 넘친다면 k - 1까지의 합은 절대로 넘치지 않음

i까지 고른건 weight고 그렇기 때문에 넘치기 전까지는 i다음(i + 1)부터 k하나 전 까지(k - 1)의 weight의 합과 같다.

 

- maxprofit : 지금까지 내가 찾은 물건들의 합 중에 가장 큰 경우의 값- bound : 해당 상태에서의 최적해의 가능성을 평가하기 위한 값

  -> 여기서 더 진행하는게 promising한가 판별할 수 있는 값

bound = 지금까지 고른 값 + 넘치기 직전까지의 값 + (전체 무게 - 최대한의 무게) * pk / wk

pk / wk는 무게 당 가격? 남는 자리 중에 가장 큰 값을 더하기..~ << item k의 단가

 

 

+ bound가 maxprofit보다 작은가?-> bound가 maxprofit보다 작다면 자식 노드를 탐색해도 더 큰 값을 얻을 수 없기 때문에 탐색 할 필요 없음(= non-promising)

 

그럼 어떻게 하면 될까요?

- 노드를 DFS나 BFS로 방문하기

- profit, weight, bound를 계산하기

- <W랑 bound>가? maxprofit이 될 때 까지 검색하기

- 없다면 backtrack

 

e.g n = 4 and W = 16

DFS tree에서 순서대로 profit / weight / bound

(0.0)에서 출발하다..

아마 $115는 bound 값?

115 = profit(0) + (i + 1)부터 k - 1까지의 profit의 합 + (최대 무게(W) - 지금 전체 무게(totweight)) *  k의 profit / k의 weight

= 0 + ( 40 + 30 ) + (16 - 7) * 5 = 70 + 9 * 5 = 11598 = (p1 값은 선택, p2값은 미선택) + (i + 1 = 3, k - 1 = 3) + W - (1번은 이미 담고 2번은 이미 버려서 이제 3까지 담을 수 있음) + 4는 담을 수 없기 때문에 k = 4= 40 + 50 + (16 - 12) *2 = 40 + 50+ 4 * 2 = 98-> tree타고 내려가면서 mp(maxprofit)보다 큰 bound값을 발견했을 때 계속 찾으러 감

Analysis : 0/1 Knapsack Problem

Q. 좋아졌나요?

A. Monte Carlo Algorithm은 O(2^(n/2)) 이고 dynamic programming은 O(2^n)이기 때문에 아무튼 좀 더 좋아졌습니다.

Q. 더 좋은 방법은 없나요?

A. 트리 순회 방식을 DFS에서 BFS로 변경하면 어떨까요?

The Breadth First Search

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); // Q에 v(root node)를 넣기?
    best = value(v); //가장 큰 값 일단 넣기
    while(!empty(Q)) { //Q가 비어있지 않다면
    	dequeue(Q, v); //Q에서 v꺼내기
        for(each child u of v) { //v의 child node u가 존재하면
        	if(value(u) is better than best) //best보다 u 좋다면
            	best = value(u); //바꾸기
            if(bound(u) is better than best) //bound가 더 크다면
            	enqueue(Q, u); //u를 타고 내려감
        }
    }
}

BFS 방식으로 해보기(ง˙∇˙)ว 

+ DFS : 가로로 타고 내려감

- (4, 1)은 너무 무거워서 promising x

- (4, 2)는 (3, 2)보다 bound가 작음

- (4, 4)는 maxprofit과 동일하기 때문에 안됨

 

 

 

 

 

 

 

 

Best First Search with Branch and Bound

Q. 더 좋은 방법이 없을까요?

A. 모든 자식노드의 bound를 계산할 수 있죠. bound가 많으면 더 좋은가요? best first search를 해보아요.

 

void best_frist_brabch_and_bound(state_space_tree T, number best) {
	priority_quere_of_node PQ;
    node u, v;
    initialize(PQ); // PQ 초기화
    v = root of T; // v == root node
    best = value(v); // root를 best로 설정
    insert(PQ, v); // PQ에 v 넣기
    while(!empty(PQ)) {
    	remove(PQ, v); //v 꺼내기
        if(bound(v) is better than best) // v가 best보다 큰가 = promising한가
        	for(each child u of v) { //v의 자식들 u?
            	if(value(u) is better than best) //v의 값이 best보다 크면
		        best = value(u);
        	if(bound(u) is better than best) // u의 bound가 best보다 크면 찾으러 감
        		insert(PQ, u); //PQ에 u넣기
      		} 
	}	 
}

(0.0)부터 출발

    - mp = 0

    - profit = 0, bound = 115

(1, 1)

    - profit(40) > mp(0)

    - mp = 40, bound = 115

(1, 2)

    - mp(40) < bound(82)

    but mp(40) > profit(0)

    -> non-promising

 

아무튼 그렇게 쭉쭉 타고 내려감..

 


 

그래서 branch and bound가 무엇이냐

1. mp(내가 지금까지 확인한 값 중에 가장 큰 값)이랑 bound(아마 이정도 되는 값을 찾을 수 있을 것)중에 bound가 더 큰가

2. profit이랑 mp랑 누가 더 큰가 -> mp가 더 크면 확인할 필요 x

3. 자식의 bound가 mp보다 더 크면 ~~(1번)

 

그래서 우리가 0/1 Knapsack Problem을 하기 위해 알아본 방식이 5개라고?

1. 아마 다이나믹 프로그래밍..(표 오백개 그리는 무언가)

2. Monte Carlo Algorithm

3. DFS(깊이 우선 탐색)

4. BFS(너비 우선 탐색 | 옆으로 타고감)

5. BFS(best first search)

아마도 이렇게 5개? 라고 합니다.

끝 !