Basic Concepts
In general, the breadth-first search strategy has no advantage over a depth-first search (backtracking).
- ๐ Backtracking with the 0-1 Knapsack problem (Depth-First Search)
- ๐ Branch-and-Bound with the 0-1 Knapsack problem (Breadth-First Search)
However, we can improve our search by using our bound to do more than just determine whether a node is promising. After visiting all the children of a given node, we can look at all the promising, unexpanded nodes and expand beyond the one with the best bound. Recall that a node is promising if its bound is better than the value of the best solution found so far. In this way, we often arrive at an optimal solution more quickly than if we simply proceeded blindly in a predetermined order. The example that follows illustrates this method.
๐ 0-1 ๋ฐฐ๋ญ ๋ฌธ์ ์ ์ต๊ณ ์ฐ์ ํ์์ ์ ์ฉํ๊ธฐ์ ์์ ๊น์ด์ฐ์ ํ์(๋ฐฑํธ๋ํน)๊ณผ ๋๋น์ฐ์ ํ์์ผ๋ก ํด๊ฒฐํ๋ ๋ฒ์ ์ดํด๋ดค๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋๋น์ฐ์ ํ์์ ๊น์ด์ฐ์ ํ์๋ณด๋ค ์ข์ ์ ์ด ์์๋ค. ํ์ง๋ง ์ต๊ณ ์ฐ์ ํ์์์๋ bound ๊ฐ์ ๋ ธ๋์ ์ ๋ง์ฑ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ฒ ์ธ์ ์ถ๊ฐ์ ์ผ๋ก ํ์ฉํ์ฌ ์๊ณ ๋ฆฌ์ฆ์ ํจ์จ์ ํฅ์์ํจ๋ค.
์ต๊ณ ์ฐ์ ํ์์ ํน์ ๋ ธ๋์ ๋ชจ๋ ์์๋ ธ๋๋ฅผ ๋ฐฉ๋ฌธํ ํ ์ ๋งํ๋ฉด์ ๋ฏธํ์ฅ๋ ๋ ธ๋ ๋ชจ๋๋ฅผ ์ดํด๋ณด๊ณ ๊ทธ ์ค bound ๊ฐ์ด ๊ฐ์ฅ ์ข์ ๋ ธ๋๋ฅผ ์ฐ์ ์ผ๋ก ํ์ฅํ๋ค. ์ง๊ธ๊น์ง ์ฐพ์ ์ต๊ณ ์ ํด๋ต๋ณด๋ค ๊ทธ bound ๊ฐ์ด ๋ ์ข๋ค๋ฉด ๊ทธ ๋ ธ๋๋ ์ ๋งํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ฏธ๋ฆฌ ๊ฒฐ์ ๋ ์์(๊น์ด์ฐ์ ํ์, ๋๋น์ฐ์ ํ์)๋๋ก ํ์์ ์งํํ๋ ๊ฒ๋ณด๋ค ๋ ๋นจ๋ฆฌ ์ต์ ์ ํด๋ฅผ ์ฐพ๊ฒ๋๋ค.
Example Suppose that n = 4, W = 16, and we have the following:
| 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 |
The pruned state space tree produced using best-first search in above Example. Stored at each node from top to bottom are the total profit of the items stolen up to that node, their total weight, and the bound on the total profit that could be obtained by expanding beyond the node. The node shaded in color is the one at which an optimal solution is found.

Step 1 Visit node (0, 0) (the root).
(a) Set its profit and weight to ๏ผ0 and 0.
(b) Compute its bound to be ๏ผ115.
(c) Set maxprofit to 0.
profit = 0
weight = 0
bound = 115(= 40 + 30 + (16 - 7) x 50/10)
maxprofit = 0
Step 2 Visit node (1, 1).
(a) Compute its profit and weight to be ๏ผ40 and 2.
(b) Because its weight 2 is less than or equal to 16, the value of W, and its profit ๏ผ40 is greater than ๏ผ0, the value of maxprofit, set maxprofit to ๏ผ40.
(c) Compute its bound to be ๏ผ115.
profit = 40
weight = 2
bound = 115
(2 <= 16(W)) && (40 > 0(=current maxprofit)) → maxprofit = 40
Step 3 Visit node (1, 2).
(a) Compute its profit and weight to be ๏ผ0 and 0.
(b) Compute its bound to be ๏ผ82
profit = 0
weight = 0
bound = 82(= 30 + 50 + (16 - 15) x 10/5)
(0 <= 16(W)) && (0 > 40(=current maxprofit)) → false
Step 4 Determine promising, unexpanded node with the greatest bound.
(a) Because node (1, 1) has a bound of ๏ผ115 and node (1, 2) has a bound of ๏ผ82, node (1, 1) is the promising, unexpanded node with the greatest bound. We visit its children next.
// ์์ง ํ์ฅํ์ง ์์ ๋
ธ๋ ์ค์์ ๊ฐ์ฅ ํฐ bound ๊ฐ์ ๊ฐ์ง ์ ๋งํ ๋
ธ๋๋ฅผ ์ฐพ๋๋ค.
// ๋
ธ๋(1,1)์ bound = 115 > ๋
ธ๋(1,2)์ bound = 82 ์ด๋ฏ๋ก,
// ๋
ธ๋(1,1)์ bound ๊ฐ์ด ๊ฐ์ฅ ํฌ๋ฉด์ ์ ๋งํ๊ณ ํ์ฅํ์ง ์์ ๋
ธ๋์ด๋ค.
// ๋ฐ๋ผ์ ๊ทธ ๋
ธ๋์ ์์๋
ธ๋(2,1)๋ฅผ ๋ค์์ผ๋ก ๋ฐฉ๋ฌธํ๋ค.
Step 5 Visit node (2, 1).
(a) Compute its profit and weight to be ๏ผ70 and 7.
(b) Because its weight 7 is less than or equal to 16, the value of W , and its profit ๏ผ70 is greater than ๏ผ40, the value of maxprofit, set maxprofit to ๏ผ70.
(c) Compute its bound to be ๏ผ115.
profit = 70
weight = 7
bound = 115
(7 <= 16(W)) && (70 > 40(=current maxprofit)) → maxprofit = 70
Step 6 Visit node (2, 2).
(a) Compute its profit and weight to be ๏ผ40 and 2.
(b) Compute its bound to be ๏ผ98.
profit = 40
weight = 2
bound = 98(= 40 + 50 + (16 - 12) x 10/5)
(2 <= 16(W)) && (40 > 70(=current maxprofit)) → false
Step 7 Determine promising, unexpanded node with the greatest bound.
(a) That node is node (2, 1). We visit its children next.
// ์์ง ํ์ฅํ์ง ์์ ๋
ธ๋ ์ค์์ ๊ฐ์ฅ ํฐ bound ๊ฐ์ ๊ฐ์ง ์ ๋งํ ๋
ธ๋๋ฅผ ์ฐพ๋๋ค.
// ๋
ธ๋(2,1)์ bound = 115 > ๋
ธ๋(2,2)์ bound = 98 > ๋
ธ๋(1,2)์ bound = 82 ์ด๋ฏ๋ก
// ๋
ธ๋(2,1)์ ์์๋
ธ๋์ธ (3,1)๋ฅผ ๋ค์์ผ๋ก ๋ฐฉ๋ฌธํ๋ค.
Step 8 Visit node (3, 1).
(a) Compute its profit and weight to be ๏ผ120 and 17.
(b) Determine that it is nonpromising because its weight 17 is greater than or equal to 16, the value of W. We make it nonpromising by setting its bound to ๏ผ0.
profit = 120
weight = 17
bound = 0
(17 <= 16(W)) && (120 > 70(=current maxprofit)) → false
// weight๊ฐ W๋ฅผ ์ด๊ณผํ์ผ๋ฏ๋ก bound ๊ฐ์ 0์ผ๋ก ๋์ ์ ๋งํ์ง ์๋ค๊ณ ํ์ํ๋ค.
Step 9 Visit node (3, 2).
(a) Compute its profit and weight to be ๏ผ70 and 7.
(b) Compute its bound to be ๏ผ80.
profit = 70
weight = 7
bound = 80(= 40 + 30 + 10)
(7 <= 16(W)) && (70 > 70(=current maxprofit)) → false
Step 10 Determine promising, unexpanded node with the greatest bound.
(a) That node is node (2, 2). We visit its children next.
// ์์ง ํ์ฅํ์ง ์์ ๋
ธ๋ ์ค์์ ๊ฐ์ฅ ํฐ bound ๊ฐ์ ๊ฐ์ง ์ ๋งํ ๋
ธ๋๋ฅผ ์ฐพ๋๋ค.
// ๋
ธ๋(2,2)์ bound = 98 > ๋
ธ๋(1,2)์ bound = 82 > ๋
ธ๋(3,2)์ bound = 80 ์ด๋ฏ๋ก
// ๋
ธ๋(2,2)์ ์์๋
ธ๋์ธ (3,3)์ ๋ค์์ผ๋ก ๋ฐฉ๋ฌธํ๋ค.
Step 11 Visit node (3, 3).
(a) Compute its profit and weight to be ๏ผ90 and 12.
(b) Because its weight 12 is less than or equal to 16, the value of W, and its profit ๏ผ90 is greater than ๏ผ70, the value of maxprofit, set maxprofit to ๏ผ90.
(c) At this point, nodes (1, 2) and (3, 2) become nonpromising because their bounds, ๏ผ82 and ๏ผ80 respectively, are less than or equal to ๏ผ90, the new value of maxprofit.
(d) Compute its bound to be ๏ผ98.
profit = 90
weight = 12
bound = 98(= 40 + 50 + (16 - 12) x 10/5)
(12 <= 16(w)) && (90 > 70(current maxprofit)) → maxprofit = 90
// 82(=๋
ธ๋(1,2)์ bound) <= 90 → ์ด ์์ ์์ ๋
ธ๋(1,2)๋ ์ ๋งํ์ง ์๋ค๊ณ ๊ฒฐ์ ๋๋ค.
// 80(=๋
ธ๋(3,2)์ bound) <= 90 → ์ด ์์ ์์ ๋
ธ๋(3,2)๋ ์ ๋งํ์ง ์๋ค๊ณ ๊ฒฐ์ ๋๋ค.
Step 12 Visit node (3, 4).
(a) Compute its profit and weight to be ๏ผ40 and 2.
(b) Compute its bound to be ๏ผ50.
(c) Determine that it is nonpromising because its bound ๏ผ50 is less than or equal to ๏ผ90, the value of maxprofit
profit = 40
weight = 2
bound = 50(= 40 + 10)
(2 <= 16(W)) && (40 > 90(current maxprofit)) → false
// 50(=๋
ธ๋(3,4)์ bound) <= 90 → ๋
ธ๋(3,4)๋ ์ ๋งํ์ง ์๋ค๊ณ ๊ฒฐ์ ๋๋ค.
Step 13 Determine promising, unexpanded node with the greatest bound.
(a) The only unexpanded, promising node is node (3, 3). We visit its children next.
// ์์ง ํ์ฅํ์ง ์์ ๋
ธ๋ ์ค์์ ๊ฐ์ฅ ํฐ bound๋ฅผ ๊ฐ์ง ์ ๋งํ ๋
ธ๋๋ฅผ ์ฐพ๋๋ค.
// ์ ์ผํ๊ฒ ํ์ฅ๋์ง ์๊ณ ๋จ์ ์ ๋งํ ๋
ธ๋๋ (3,3)์ด๋ค.
// ๊ทธ ๋
ธ๋์ ์์๋
ธ๋์ธ (4,1)์ ๋ค์์ผ๋ก ๋ฐฉ๋ฌธํ๋ค.
Step 14 Visit node (4, 1).
(a) Compute its profit and weight to be ๏ผ100 and 17.
(b) Determine that it is nonpromising because its weight 17 is greater than or equal to 16, the value of W. We set its bound to ๏ผ0.
profit = 100
weight = 17
bound = 0
(17 <= 16(W)) && (100 > 90(current maxprofit)) → false
// weight๊ฐ W๋ฅผ ์ด๊ณผํ์ผ๋ฏ๋ก bound ๊ฐ์ 0์ผ๋ก ๋์ ์ ๋งํ์ง ์๋ค๊ณ ํ์ํ๋ค.
Step 15 Visit node (4, 2).
(a) Compute its profit and weight to be ๏ผ90 and 12.
(b) Compute its bound to be ๏ผ90.
(c) Determine that it is nonpromising because its bound ๏ผ90 is less than or equal to ๏ผ90, the value of maxprofit. Leaves in the state space tree are automatically nonpromising because their bounds cannot exceed maxprofit.
profit = 90
weight = 12
bound = 90(= 40 + 50)
(12 <= 16(W)) && (90 > 90(current maxprofit)) → false
// 90(=๋
ธ๋(4,2)์ bound) <= 90 → ๋
ธ๋(4,2)๋ ์ ๋งํ์ง ์๋ค๊ณ ๊ฒฐ์ ํ๋ค.
Step16 Because there are now no promising, unexpanded nodes, we are done.
// ์ํ๊ณต๊ฐํธ๋ฆฌ์์ ์๋
ธ๋๋ค์ ๊ทธ bound ๊ฐ์ด maxprofit์ ๋์ ์ ์์ผ๋ฏ๋ก
// ์๋์ผ๋ก ์ ๋งํ์ง ์๊ฒ ๋๋ค. ์ ๋งํ๋ฉด์ ๋ฏธํ์ฅ๋ ๋
ธ๋๊ฐ ์์ผ๋ฏ๋ก ์๊ณ ๋ฆฌ์ฆ์ด ์ข
๋ฃ๋๋ค.
It must be stressed, however, that there is no guarantee that the node that appears to be best will actually lead to an optimal solution. In Example, node (2,1) appears to be better than node (2,2), but node (2,2) leads to the optimal solution. In general, best-first search can still end up creating most or all of the state space tree for some instances.
๐ ์์ ์์ ์์ ๋ ธ๋(2,1)์ด ๋ ธ๋(2,2)๋ณด๋ค ๋ ์ข์๋ณด์์ง๋ง ๋ ธ๋(2,2)๊ฐ ํด๋ต์ ์ด๋์ด๋ธ๋ค. ์ฆ, ์ต๊ณ ๋ผ๊ณ ์ฌ๊ฒจ์ง๋ ๋ ธ๋์์ ์ต์ ์ ํด๊ฐ ๋์จ๋ค๋ ๋ณด์ฅ์ ์๋ค.
The Best-First Search with Branch-and-Bound Pruning Algorithm for the 0-1 Knapsack Problem
Algorithm Design
To determine whether the node is promising, we initialize totweight and bound to weight and profit, respectively, and then greedily grab items, adding their weights and profits to totweight and bound, until we reach an item whose weight would bring totweight above W . We grab the fraction of that item allowed by the available weight, and add the profit of that fraction to bound. In this way, bound becomes an upper bound on the amount of profit we could obtain by expanding beyond the node. If the node is at level i, and the node at level k is the one whose weight would bring the weight above W, then
$$ \begin{align} totweight &= weight + \sum_{j=i+1}^{k-1}w_j, \quad \text{and} \notag{}\\ bound &= \left(profit + \sum_{j=i+1}^{k-1}p_j\right) + (W - totweight) \times \frac{p_k}{w_k} \notag{} \end{align} $$
- profit: the sum of the profits of the items included up to the node.
- weight: the sum of the weights of those items.
- totweight: the sum of the weights could be obtained by expanding beyond that node (W๋ฅผ ์ด๊ณผํ ์ ์๋ค.)
- bound: the upper bound on the profit that could be obtained by expanding beyond that node.
Recall that a node is also nonpromising if
$$ weight \le W $$
The implementation of best-first search consists of a simple modification to breadth-first search. Instead of using a queue, we use a priority queue. In the algorithm, insert (PQ, v) is a procedure that adds v to the priority queue PQ, whereas remove (PQ, v) is a procedure that removes the node with the best bound and assigns its value to v.
๐ ๋๋น์ฐ์ ํ์์ ์กฐ๊ธ ๋ณํํ๋ฉด ์ต๊ณ ์ฐ์ ํ์์ ๊ตฌํํ ์ ์๋ค. ์ต๊ณ ์ bound ๊ฐ์ ๊ฐ์ง ๋ ธ๋๋ฅผ ์ฐ์ ์ ์ผ๋ก ์ ํํ๊ธฐ ์ํด ๋จ์ ํ ๋์ ์ฐ์ ์์ ํ(Priority Queue)๊ฐ ์ฌ์ฉ๋๋ค. insert(PQ, v)๋ v๊ฐ์ ์ฐ์ ์์ ํ์ ์ถ๊ฐํ๊ณ , remove
(PQ, v)๋ ์ต๊ณ bound ๊ฐ์ ๊ฐ๋ ๋ ธ๋๋ฅผ ์ฐ์ ์์ ํ์์ ์ ๊ฑฐํ๋ฉด์ ๊ทธ ๊ฐ์ v์ ํ ๋นํ๋ค.
Besides using a priority queue instead of a queue, we have added a check following the removal of a node from the priority queue. The check determines if the bound for the node is still better than best. This is how we determine that a node has become nonpromising after visiting the node. For example, node (1, 2) in the above Exampe(Step 3) is promising at the time we visit it. In our implementation, this is when we insert it in PQ. However, it becomes nonpromising when maxprofit takes the value ๏ผ90(Step 11). In our implementation, this is before we remove it from PQ. We learn this by comparing its bound with maxprofit after removing it from PQ. In this way, we avoid visiting children of a node that becomes nonpromising after it is visited.
๐ ์ต๊ณ ์ฐ์ ํ์์ ์ฐ์ ์์ ํ์์ ๋ ธ๋๋ฅผ ์ ๊ฑฐํ ๋ค ํน์ ๋ ธ๋์ bound ๊ฐ์ด ์ฌ์ ํ maxprofit ๋ณด๋ค ๋์์ง๋ฅผ ํ์ธํ๋ค. ์๋ฅผ ๋ค์ด, ์์ ์์ Step11์์ maxprofit์ ๊ฐ์ด 90์ด ๋ ํ์ ๋ ธ๋(1,2) ๋ฐ ๋ ธ๋(3,2)๊ฐ ๋ ์ด์ ์ ๋งํ์ง ์์์ ํ์ธํ ๊ฒ์ด๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํน์ ๋ ธ๋์ ๋ฐฉ๋ฌธ ํ ์ ๋งํ์ง ์๊ฒ ๋ ๋ ธ๋์ ์์ ๋ ธ๋๋ฅผ ๋ฐฉ๋ฌธํ์ง ์์๋ ๋์ด ์๊ณ ๋ฆฌ์ฆ์ ํจ์จ์ฑ์ด ๊ฐ์ ๋๋ค.
Pseudocode
- The Best-First Search with Branch-and-Bound Pruning Algorithm for the 0-1 Knapsack Problem
// We will use the following data type in the algorithm.
struct node
{
int level; // the node's level in the tree
int profit;
int weight;
float bound;
}
// Pseudocode: The Best-First Search Branch-and-Bound Pruning Algorithm
// for the 0-1 Knapsack problem
void knapsack3(int n, const int p[], cont int w[], int W, int &maxprofit)
// Problem: Let n items be given, where each item has a weight and a profit.
// The weights and profits are positive integers. Furthermore, let a positive
// integer W be given. Determine a set of items with maximum total profit,
// under the constraint that the sum of their weights cannot exceed W.
// Inputs: positive integers n and W, arrays of positive integers w and p,
// each indexed from 1 to n, and each of which is sorted in nonincreasing
// order according to the values of p[i] / w[i].
// Outputs: an integer maxprofit that is the sum of the profits of
// an optimal set.
{
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(Q)) { // Remove nod with
remove(PQ, v); // best bound
if(v.bound > maxprofit) { // Check if node is still
u.level = v.level + 1; // promising.
u.profit = v.profit + p[u.level];
u.weight = v.weight + w[u.level];
if ((u.weight <= W) && (u.profit > maxprofit))
maxprofit = u.profit;
u.bound = bound(u);
if (bound(u) > maxprofit)
insert (PQ, u);
u.weight = v.weight; // Set u to the child
u.profit = v.profit; // that does not include
u.bound = bound(u); // the next item.
if (u.bound > maxprofit)
insert (PQ, u);
}
}
}
/* Function bound is the same */
Source Code
- knapsack_bestfs.h
// File: knapsack_bestfs.h
#ifndef KNAPSACK_BESTFS_H
#define KNAPSACK_BESTFS_H
#include "pqueue.h" // Provides priority_queue
using namespace data_structures; // for node
namespace algorithms
{
void knapsack3(int n, const int p[ ], const int w[ ], int W, int& maxprofit);
// Problem: Let n items be given, where each item has a weight and
// a profit. The weights and profits are positive integers. Furthermore,
// let a positive integer W be given. Determine a set of items with
// maximum total profit, under the constraint that the sum of their
// weights cannot exceed W .
// Inputs: positive integers n and W , arrays of positive integers
// w and p, each indexed from 1 to n, and each of which is sorted in
// nonincreasing order according to the values of p[i] / w [i].
// Outputs: an integer maxprofit that is the sum of the profits in an
// optimal set.
float bound(node u, int n, const int p[ ], const int w[ ], int W);
}
#endif
- knapsack_bestfs.cpp
// File: knapsack_bestfs.cpp
#include <cassert> // Provides assert
#include <iostream> // Provides cout and endl
#include <iomanip>
#include "knapsack_bestfs.h"
using namespace std;
namespace algorithms
{
void knapsack3(int n, const int p[ ], const int w[ ], int W, int& maxprofit)
{
int prm_node_cnt = 0; // The number of promising nodes
int nprm_node_cnt = 0; // The number of non-promising nodes
priority_queue PQ;
node u, v;
assert(PQ.is_empty( )); // Initialize PQ to be empty.
v.level = 0; v.profit = 0; v.weight = 0; // Initialize v to be the root.
maxprofit = 0;
v.bound = bound(v, n, p, w, W);
PQ.insert(v);
while (!PQ.is_empty( ))
{
v = PQ.get_front( ); // Remove node with best bound.
cout << "level: " << setw(1) << v.level << setw(10)
<< "profit: " << setw(2) << v.profit << setw(10)
<< "weight: " << setw(2) << v.weight << setw(10)
<< "bound: " << setw(2) << v.bound << endl;
if (v.bound > maxprofit) // Check if node is still promising.
{
// Set u to the child that includes the next item.
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)
maxprofit = u.profit;
u.bound = bound(u, n, p, w, W);
if (u.bound > maxprofit)
PQ.insert(u);
else
{
// Count the number of non-promising nodes
++nprm_node_cnt;
}
// Set u to the child that does not include the next item.
u.weight = v.weight;
u.profit = v.profit;
u.bound = bound(u, n, p, w, W);
if (u.bound > maxprofit)
PQ.insert(u);
else
{
// Count the number of non-promising nodes
++nprm_node_cnt;
}
// Count the number of promising nodes
++prm_node_cnt;
}
else
{
// Count the number of non-promising nodes
++nprm_node_cnt;
}
}
cout << endl << "The number of promising node: " << prm_node_cnt << endl;
cout << "The number of non-promising node: " << nprm_node_cnt << endl;
}
float bound(node u, int n, const int p[ ], const int w[ ], int W)
{
int j, k;
int totweight;
float result;
if (u.weight >= W)
return 0;
else
{
result = (float)u.profit;
j = u.level + 1;
totweight = u.weight;
while (j <= n && totweight + w[j] <= W)
{
// Grab as many items as possible.
totweight = totweight + w[j];
result = result + p[j];
++j;
}
k = j; // Use k for consistency with formula in text.
if (k <= n) // Grab fraction of kth item.
result = result + (W - totweight) * (p[k] / w[k]);
return result;
}
}
}
- maxtotprofit.cpp
// File: maxtotprofit.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "knapsack_bestfs.h"
using namespace std;
using namespace algorithms;
const int n = 4;
const int W = 16;
int w[n+1] = {0, 2, 5, 10, 5}; // w[0] is meaningless
int p[n+1] = {0, 40, 30, 50, 10}; // p[0] is meaningless
int main( )
{
clock_t start, end;
int maxprofit = 0;
start = clock( );
knapsack3(n, p, w, W, maxprofit);
end = clock( );
cout << "The answer: " << maxprofit << endl;
double result = (double)(end-start) / CLOCKS_PER_SEC;
cout << "Elpased time is: "<< result << " sec." << endl;
return EXIT_SUCCESS;
}
Time Complexity Analysis
Worst-Case Time Complexity
$\displaystyle O(n) = 1 + 2 + 2^2 + 2^3 + … + 2^n = 2^{(n+1)} - 1 \in \Theta(2^n)$
๐ $w_i$๋ฅผ ํฌํจ์ํค๋๋ ๊ทธ๋ ์ง ์๋๋์ ๋ ๊ฐ์ง ์ ํ์ด๋ฏ๋ก ์ํ๊ณต๊ฐํธ๋ฆฌ ๋ด ์ ์ฒด ๋ ธ๋์ ์๋ ์ต๋ $2^{n+1}-1$๊ฐ๊ฐ ๋๋ค. ์ต์ ์ ๊ฒฝ์ฐ ๋ฐฉ๋ฌธํ๋ ๋ ธ๋์ ์๊ฐ ์ง์์ด์ง๋ง, ๊ฐ์ง์น๊ธฐ๋ฅผ ํตํด ์ํ๋ ธ๋์ ์๋ฅผ ์ค์ผ ์ ์๊ธฐ ๋๋ฌธ์ ์ต๊ณ ์ฐ์ ํ์ ๊ธฐ๋ฒ์ ์ฌ์ฉํ ์ด ์๊ณ ๋ฆฌ์ฆ์ ํจ์จ์ ๋ ์ข์ ์ ์๋ค.
Comparing this Algorithm with Other Techniques
| Problem | Algorithm Technique | Worst-Case Time Complexity |
| 0-1 Knapsack | Dynamic Programming | $O(min(2^n, nW))$ |
| Backtracking(depth-first search) | $\Theta(2^{n})$ | |
| Branch-and-Bound(breadth-first search) | $\Theta(2^{n})$ | |
| Branch-and-Bound(best-first search) | $\Theta(2^{n})$ |
Using best-first search, we have checked only 11 nodes, which is 6 less than the number checked using breadth-first search and 2 less than the number checked using depth-first search. A savings of 2 is not very impressive; however, in a large state space tree, the savings can be very significant when the best-first search quickly hones in on an optimal solution.
๐ ์์ ์์ ์์ ์ต๊ณ ์ฐ์ ํ์์ ์ฌ์ฉํ์ฌ 11๊ฐ์ ๋ ธ๋๋ง ํ์ธํ๋๋ฐ, ์ด๋ ๋๋น์ฐ์ ํ์์ ์ฌ์ฉํ์ฌ ํ์ธํ ๋ ธ๋ ์๋ณด๋ค 6๊ฐ ์ ๊ณ , ๊น์ด ์ฐ์ ํ์์ ์ฌ์ฉํ์ฌ ํ์ธํ ๋ ธ๋ ์๋ณด๋ค 2๊ฐ ์ ๋ค. 2๊ฐ์ ๋ ธ๋๋ฅผ ์ ์ฝํ๋ ๊ฒ์ ๊ทธ๋ค์ง ์ธ์์ ์ด์ง ์์ ์๋ ์๋ค. ํ์ง๋ง ๋๊ท๋ชจ ์ํ๊ณต๊ฐํธ๋ฆฌ์์ ์ต๊ณ ์ฐ์ ํ์์ด ์ต์ ์ ํด๋ฅผ ๋น ๋ฅด๊ฒ ์ฐพ์ ๋ ๊ทธ ํจ๊ณผ๋ ๋งค์ฐ ํด ์ ์๋ค.
nW ๋๋ถ์ ๋์ ๊ณํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๊ฒ ๋ ์ข์ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์๋ค. ๊ทธ๋ฌ๋ ๊น์ด์ฐ์ ํ์, ๋๋น์ฐ์ ํ์, ์ต๊ณ ์ฐ์ ํ์ ์๊ณ ๋ฆฌ์ฆ์์ ์ต์ ์ ๊ฒฝ์ฐ๋ฅผ ๋ฐ์ง๋ฉด ์ค์ ๋ฐฉ๋ฌธํ๋ ๋ ธ๋์ ์๋ฅผ ์ผ๋ง๋ ์ ์ฝํ๋์ง ๋ฐ์์ด ์๋๋ฏ๋ก, ์๊ณ ๋ฆฌ์ฆ์ ์๋์ ์ธ ํจ์จ์ ์ด๋ก ์ ์ผ๋ก ๋ถ์ํ๊ธฐ๋ ์ด๋ ต๋ค.
Exercises
Use The Breadth-First Search with Branch-and-Bound Pruning algorithm for the 0-1 Knapsack problem to maximize the profit for the following problem instance. Suppose that n = 5, W = 13, and we have the following:
| i | $p_i$ | $w_i$ | $p_i/w_i$ |
| 1 | $20 | 2 | $10 |
| 2 | $30 | 5 | $6 |
| 3 | $35 | 7 | $5 |
| 4 | $12 | 3 | $4 |
| 5 | $3 | 1 | $3 |
My Answer
level: 0 profit: 0 weight: 0 bound: 80
level: 1 profit: 20 weight: 2 bound: 80
level: 2 profit: 50 weight: 7 bound: 80
level: 2 profit: 20 weight: 2 bound: 70
level: 3 profit: 55 weight: 9 bound: 70
level: 4 profit: 67 weight: 12 bound: 70
level: 1 profit: 0 weight: 0 bound: 69
level: 3 profit: 50 weight: 7 bound: 65
The number of promising node: 6
The number of non-promising node: 7
The answer: 70
Elpased time is: 0.045 sec.
