Daniel Sutantyo
Department of Computing
Macquarie University
void selection_sort(int arr[]){
for (int i = 0; i < n-1; i++){
int min_index = i;
for (int j = i+1; j < n; j++){
if (arr[j] < arr[min_index])
min_index = j;
}
swap(i,min_index);
}
}
"The subarray A[0 .. i-1] is in sorted order and all the values in A[0 .. i-1] are smaller than or equal to the values in A[i..n-1]"
selection sort
void selection_sort(int arr[]){
int n = arr.length; // added this line
for (int i = 0; i < n-1; i++){
int min_index = i;
for (int j = i+1; j < n; j++){
if (arr[j] < arr[min_index])
min_index = j;
}
swap(i,min_index);
}
}
Input: [ 17 41 15 33 66 24 91 60 ]
Initialisation: i = 0
void selection_sort(int arr[]){
int n = arr.length; // added this line
for (int i = 0; i < n-1; i++){
int min_index = i;
for (int j = i+1; j < n; j++){
if (arr[j] < arr[min_index])
min_index = j;
}
swap(i,min_index);
}
}
Array: [ 15 41 17 33 66 24 91 60 ]
To convince yourself (or others), you may want to show that the loop invariant is still correct after we perform the 1st of the loop (i.e. i = 1)
Array: [ 15 17 24 33 66 41 91 60 ]
Maintenance: assume the loop invariant is true when i = k
show the loop invariant is true when i = k + 1
k
Array: [ 15 17 24 33 41 60 66 91 ]
Termination: loop guard is i < n-1, hence at termination i = n-1
void selection_sort(int arr[]){
int n = arr.length; // added this line
for (int i = 0; i < n-1; i++){
int min_index = i;
for (int j = i+1; j < n; j++){
if (arr[j] < arr[min_index])
min_index = j;
}
swap(i,min_index);
}
}
Array: [ 15 17 24 33 41 60 66 91 ]
void selection_sort(int arr[]){
int n = arr.length; // added this line
for (int i = 0; i < n-1; i++){
int min_index = i;
for (int j = i+1; j < n; j++){
if (arr[j] < arr[min_index])
min_index = j;
}
swap(i,min_index);
}
}
int eval(int[] c, int x) {
int y = 0, t = 1, n = c.length-1;
for (int i = 0; i <= n; i++) {
y = y + t * c[i];
t = t * x;
}
return y;
}
\( i = 0\quad\rightarrow\quad y = c_0\)
polynomial evaluation
\[ f(x) = c_nx^n + c_{n-1}x^{n-1} + \cdots +c_1x + c_0 \]
\( i =1\quad\rightarrow\quad y = c_0 + c_1x\)
\( i =2\quad\rightarrow\quad y = c_0 + c_1x + c_1x^2\)
in the end, will we have \( y = c_0 + c_1x + c_1x^2 + \cdots + c_nx^n\)?
int eval(int[] c, int x) {
int y = 0, t = 1, n = c.length-1;
for (int i = 0; i <= n; i++) {
y = y + t * c[i];
t = t * x;
}
return y;
}
\[ y = \sum_{j = 0}^{i-1} c_jx^j = c_0 + c_1x + \cdots + c_{i-1}x^{i-1}\]
Loop invariant:
\[ i = 0\quad\rightarrow\quad y = \sum_{j = 0}^{-1} c_jx^j = 0, t = x^0 = 1 \]
Initialisation: i = 0, t = 1, y = 0
\[t = x^i\]
int eval(int[] c, int x) {
int y = 0, t = 1, n = c.length-1;
for (int i = 0; i <= n; i++) {
y = y + t * c[i];
t = t * x;
}
return y;
}
\[ i = 1\quad\rightarrow\quad y = \sum_{j = 0}^{0} c_jx^j = c_0, t = x \]
\[ y = \sum_{j = 0}^{i-1} c_jx^j = c_0 + c_1x + \cdots + c_{i-1}x^{i-1}\]
Loop invariant:
\[t = x^i\]
Maintenance: assume the loop invariant is true when i = k
show the loop invariant is true when i = k + 1
\[ y = \sum_{j = 0}^{k-1} c_jx^j = c_0 + c_1x + \cdots + c_{k-1}x^{k-1}, \qquad t = x^k\]
\[ y = \sum_{j = 0}^{i-1} c_jx^j = c_0 + c_1x + \cdots + c_{i-1}x^{i-1}\]
Loop invariant:
\[t = x^i\]
int eval(int[] c, int x) {
int y = 0, t = 1, n = c.length-1;
for (int i = 0; i <= n; i++) {
y = y + t * c[i];
t = t * x;
}
return y;
}
\[ i = n+1\quad\rightarrow\quad y = \sum_{j = 0}^{n} c_jx^j = c_0 + c_1x + \cdots + c_nx^n, t = x^{n+1} \]
\[ y = \sum_{j = 0}^{i-1} c_jx^j = c_0 + c_1x + \cdots + c_{i-1}x^{i-1}\]
Loop invariant:
\[t = x^i\]
Termination: the loop guard is i <= n, hence at termination, i = n+1
from the previous slide, we proved that the loop invariant is true at termination of the loop, and so we have
the correctness of the algorithm follows immediately from the loop invariant
exhaustive search
complete search
generate and test
brute-force algorithms
😎
😎
intractable solution
for
a tractable problem
intractable solution
for
intractable problem
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
\[n * (n-1) * \cdots * (n-k+1) = \frac{n!}{(n-k)!}\]
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
\[\frac{n!}{k!(n-k)!} = \binom{n}{k}\]
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
1 4 6 4 1
a b c d
a b c d
a b c
a b d
a c d
b c d
a b
a c
a d
b c
b d
c d
a
b
c
d
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
1 4 6 4 1
\(2^4 = 16\)
1 5 10 10 5 1
\(2^5 =32\)
1 3 3 1
\(2^3 = 8\)
a b c d
\(\frac{0}{1}\)
a d
b c d
c
1 0 0 1
\(\frac{0}{1}\)
\(\frac{0}{1}\)
\(\frac{0}{1}\)
0 1 1 1
0 0 1 0
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
\[(x+y)^4 = x^4 + 4x^3y + 6x^2y^2 + 4xy^3 + y^3\]
\[(x+y)^n = \sum_{k=0}^n \binom{n}{k} x^ky^{n-k}\]
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
permutations and combinations
(references: CLRS, Appendix C, Section C.1)
\((n-1)!\) ways (why not \(n!\) ?)
A
B
C
D
E
A
B
C
D
E
We have a bunch of metallic bars with known lengths. Sometimes we need to produce a bar of a certain length from the bars that we have.
We are not allowed to cut up any metallic bar, but we can solder any two rods together to create a longer bar.
We have a bunch of metallic bars with known lengths. Sometimes we need to produce a bar of a certain length from the bars that we have.
We are not allowed to cut up any metallic bar, but we can solder any two rods together to create a longer bar.
We have a bunch of metallic bars with known lengths. Sometimes we need to produce a bar of a certain length from the bars that we have
We are not allowed to cut up any metallic bar, but we can solder any two rods together to create a longer bar
\[\sum_{j=0}^k b_{i_j} = L\]
for (int i = 0; i < b.length; i++){
for (int j = 0; j < b.length; j++){
for (int k = 0; k < b.length; k++){
for (int l = 0; l < b.length; l++){
for (int m = 0; m < b.length; m++){
...
}}}}}
public static boolean solve(int[] b, int i, int L) {
// if L == 0, we are done
if (L == 0){
return true;
}
// if we get to the end of array but still can't make the sum,
// return false
if (i >= b.length) {
return false;
}
// else keep on going with the remaining sum
return solve(b,i+1,L-b[i]) || solve(b,i+1,L);
}
[10,12,5,7,11] L = 25
[12,5,7,11] L = 15
[12,5,7,11] L = 25
don't pick 10
pick 10
[5,7,11] L = 3
[5,7,11] L = 15
[5,7,11] L = 15
[5,7,11] L = 25
don't pick 12
pick 12
pick 12
don't pick 12
[7,11] L = -2
[11] L = -9
pick 5
pick 7
...
[7,11] L = 15
[11] L = 8
pick 7
don't pick 5
don't pick 5
...
...
...
...
don't pick 7
...
[11] L = 15
[7,11] L = 15
pick 5
...
...
"a"
""
"ab"
"a"
"b"
""
"abc"
"ab"
"ac"
"a"
"bc"
"b"
"c"
a ?
b ?
c ?
""
""
d ?
"abd"
"ab"
"bcd"
"bc"
"d"
""
... ...
... ...
... ...
(and so on)
"a" "b" "c" ..... "9" "0"
"a" "b" "c" ..... "9" "0"
public static boolean solve(int[] b, int i, int L) {
// if L == 0, we are done
if (L == 0){
return true;
}
// if we get to the end of array but still can't make the sum,
// return false
if (i >= b.length) {
return false;
}
// else keep on going with the remaining sum
return solve(b,i+1,L-b[i]) || solve(b,i+1,L);
}
DFS or BFS
[10,12,5,7,11] L = 25
[12,5,7,11] L = 15
[12,5,7,11] L = 25
don't pick 10
pick 10
[5,7,11] L = 3
[5,7,11] L = 15
[5,7,11] L = 15
[5,7,11] L = 25
don't pick 12
pick 12
pick 12
don't pick 12
[7,11] L = -2
[11] L = -9
pick 5
pick 7
...
[7,11] L = 15
[11] L = 8
pick 7
don't pick 5
don't pick 5
...
...
...
...
don't pick 7
...
[11] L = 15
[7,11] L = 15
pick 5
...
...
DFS or BFS
"a"
""
"ab"
"a"
"b"
""
"abc"
"ab"
"ac"
"a"
"bc"
"b"
"c"
a ?
b ?
c ?
""
""
d ?
"abd"
"ab"
"bcd"
"bc"
"d"
""
... ...
... ...
... ...
(and so on)
DFS or BFS
recursive backtracking
"a"
""
"ab"
"a"
"b"
""
"abc"
"ab"
"ac"
"a"
"bc"
"b"
"c"
a ?
b ?
c ?
""
""
d ?
"abd"
"ab"
"bcd"
"bc"
"d"
""
... ...
... ...
backtrack
(and so on)
branch and bound
branch and bound
We have a bunch of metallic bars with known lengths. Sometimes we need to produce a bar of a certain length from the bars that we have.
We are not allowed to cut up any metallic bar, but we can solder any two rods together to create a longer bar.
branch and bound
branch and bound
[ 50, 2, 18, 11, 9, 23, 5, 10, 30, 6, 17 ] L = 27
[2, 18, 11, ..., 17 ] L = -23
[2, 18, 11, ..., 17 ] L = 27
don't pick 50
pick 50
[18, 11, ... , 17] L = -25
don't pick 2
pick 2
pick 2
don't pick 2
...
...
...
...
...
...
[18, 11, ... , 17] L = -23
[18, 11, ... , 17] L = 25
[18, 11, ... , 17] L = 27
...
...
branch and bound
public static boolean solve(int[] b, int i, int L) {
// if L == 0, we are done
if (L == 0){
return true;
}
// if L is negative or we get to the end of the array
// return false
if (i >= b.length || L < 0) {
return false;
}
// else keep on going with the remaining sum
return solve(b,i+1,L-b[i]) || solve(b,i+1,L);
}
branch and bound
branch and bound
branch and bound
public static boolean solve(int[] b, int i, int L) {
// if L == 0, we are done
if (L == 0){
return true;
}
// if L is negative or we get to the end of the array
// return false
if (i >= b.length || L < 0) {
return false;
}
// else keep on going with the remaining sum
return solve(b,i+1,L-b[i]) || solve(b,i+1,L);
}
branch and bound
public static boolean solve(int[] b, int i, int L) {
// if L == 0, we are done
if (L == 0){
return true;
}
// if L is negative or we get to the end of the array
// return false
if (i >= b.length || L < 0 || sum(b,i) < L) {
return false;
}
// else keep on going with the remaining sum
return solve(b,i+1,L-b[i]) || solve(b,i+1,L);
}
branch and bound
branch and bound
heuristics
heuristics
heuristics
L = 48 [ 18, 11, 10, 6 ]
[ 17, 11, 10, 9 ]
heuristics methods
general tips
general tips
// this here is a C++ code
// n is the size of the array
for (i = 0; i < (1 << n); i++){
sum = 0;
for (int j = 0; j < n; j++)
if (i & (1 << j))
sum = sum + b[j];
}
i : 0 to \(2^n\)
i : 110000010
j : 100000000
j : 010000000
j : 000000010
pick b[8]
pick b[7]
pick b[1]
exhaustive search