Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
23 views

Week8 9 Chap5 Dynamic Programming

Uploaded by

Ha Minh Duc
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views

Week8 9 Chap5 Dynamic Programming

Uploaded by

Ha Minh Duc
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 60

APPLIED ALGORITHMS

APPLIED ALGORITHMS
DYNAMIC PROGRAMMING

3
CONTENTS

• Introduction to dynamic programming


• Examples
• Dynamic Programming with Bitmasking (TSP)

4
History of dynamic programming

• R.E.Bellman (1920-1984)

5
What is dynamic programming ?

• How many ways to travel from point 1 to point 8?

1 2 3 4 5 6 7 8

6
What is dynamic programming ?

• Dynamic programming
• Divide the original problem into overlapping subproblems
• Recurrence relations
• Solution to a subproblem is specified based on solutions to smaller subproblems
• Top-down approach (by recursion):
• Solve subproblems are solved recursively
• Base-case: solutions to the smallest subproblems are computed trivially (no recursion)
• Bottom-up:
• Smallest subproblems are solved trivially
• Specify the solution to each subproblem based on the solutions to smaller subproblems
(using recurrence relations)
• Do not find the solution to the same problem more than one time (memorization)

7
Top-Down implementation with memorized recursion

map <problem, value> Memory;


value DP(problem P) {
if (is_base_case(P))
return base_case_value(P);

if (Memory.find(P) != Memory.end())
return Memory [P];

value result = some value ;


for (problem Q in subproblems(P))
result = Combine(result, DP(Q));

Memory [P] = result ;


return result ;
}

8
Fibonacci numbers

• The first two numbers of Fibonacci sequence are 1 and 1. All other numbers in the sequence are
calculated as the sum of the two numbers immediately preceding them in the sequence.
• Requirement: Calculate the nth Fibonacci number
• Try to solve the problem by using dynamic programming
1. Find recursive formular:

9
Fibonacci numbers

• Store calculated results

map<int, int> mem;

int Fib(int n){


if (n <= 2) return 1;

if (mem.find(n) != mem.end())
return mem[n];

int res = Fib(n - 1) + Fib(n - 2);


mem[n] = res;

return res;
}

10
Fibonacci numbers

const int N = 1e4 + 5;


int mem[N];
memset(mem, -1, sizeof(mem));

int Fib(int n){


if (n <= 2) return 1;

if (mem[n] != -1) return mem[n];

int res = Fib(n - 1) + Fib(n - 2);


mem[n] = res;

return res;
}
• What is the complexity ?

11
Fibonacci numbers: Complexity

• There are n possible inputs for the recursive function: 1, 2, ..., n


• For each input:
• Either the results are calculated and stored
• Or retrieve it from memory if it has been calculated before
• Each input will be calculated at most once
• The computation time is O(n x f), where f is the computation time of the function
for one input, assuming that the previously computed result will be retrieved
directly from memory, in only O(1)
• As we only spend a constant amount of calculation on one input of the function, so
f = O(1)
• Total computation time is O(n)

12
CONTENTS

• Introduction to dynamic programming


• Fibonacci numbers
• Money change
• The longest ascending subsequence (Dãy con tăng dài nhất)
• Longest common subsequence (Dãy con chung dài nhất)
• Bitmask

13
Money change

• Given a set of coins with denominations D1, D2, ..., Dn and an amount of money X.
Find the minimum number of coins to exchange for X.
• Like the knapsack problem?
• Is there a greedy algorithm to solve this problem?
• The knapsack problem learned in Discrete Mathematics is solved using the branch
and bound algorithm. The greedy algorithm is not certain of providing the optimal
solution, and in many cases cannot even provide the solution...
• Try using the Dynamic Programming method!
• Finally, make comments on different approaches to solving this problem

14
Money change: dynamic programming formular

First step: build the dynamic programming


• Let MinCoin(i, x) be the minimum amount of money needed to exchange
denomination x if only the denominations D1, D2, ..., Di are allowed to be used.
• Base case:

• Recurrence relation:

15
Money change: Implementation

const int INF = 1e9; const int N = 20;


const int XMAX = 1e5 + 5;
int D[N], mem[N][XMAX];
memset(mem, -1, sizeof(mem));

int MinCoin(int i, int x){


if (x < 0 || i == 0) return INF;
if (x == 0) return 0;

if (mem[i][x] != -1) return mem[i][x];


int res = INF;
res = min(res, 1 + MinCoin(i, x - D[i]));
res = min(res, MinCoin(i - 1, x));

return mem[i][x] = res;


}
16
Money change: Complexity

• Total calculation time is O(nx)


• How to determine which coins are used in the optimal solution?
• Let's trace the recursive process back

17
Money change: Tracing using recursion​

void Trace(int i, int x) {


if (x <= 0 || i == 0) return;

if (mem[i][x] == 1 + mem[i][x - D[i]]){


cout << D[i] << ' ';
Trace(i, x - D[i]);
} else Trace(i - 1, x);
}

• Call Trace(n, x);


• The complexity of Trace function? O(max(n, x))

18
CONTENTS

• Introduction to dynamic programming


• Fibonacci numbers
• Money change
• The longest increasing subsequence
• Longest common subsequence
• Bitmask

19
Longest increasing subsequence (LIS)

• Given a sequence of n integers A[1], A[2], ..., A[n]. Find the length of the longest
increasing subsequence.
• Definition: If delete 0 or some elements of the sequence A, a subsequence of A will
be obtained.
Example: A = [2, 0, 6, 1, 2, 9]
• [2, 6, 9] is a subsequence of A
• [2, 2] is a subsequence of A
• [2, 0, 6, 1, 2, 9] is a subsequence of A
• [] is a subsequence of A
• [9, 0] is not a subsequence of A
• [7] is not a subsequence of A

20
Longest increasing subsequence (LIS)

• An ascending subsequence of A is a subsequence of A such that the elements are


strictly increasing from left to right
• [2, 6, 9] and [1, 2, 9] are two increasing subsequences of A = [2, 0, 6, 1, 2, 9]
• How to calculate length of longest increasing subsequence?
• There are 2n subsequences, the simplest method is to traverse all of these
sequences
• The complexity of this algorithm is O(n x 2n), it thus can only run quickly (e.g., within 1
second) to produce results with n ≤ 23.
• Try the Dynamic Programming method!

21
Longest increasing subsequence (LIS)

• Let LIS(i) be the length of the longest increasing subsequence of the array A[1],
A[2], ..., A[i] that ends at the ith element.
• Base case: LIS(1) = 1
• Recurrence relation:

22
Longest increasing subsequence (LIS)

const int N = 1e4 + 5;


int a[N], mem[N];
memset(mem, -1, sizeof(mem));

int LIS(i) {
if (mem[i] != -1) return mem[i];

int res = 1;
for (int j = 1; j < i; j++){
if (a[j] < a[i])
res = max(res, 1 + LIS(j));
}
mem[i] = res;

return res;
}
23
Longest increasing subsequence (LIS)

• The length of the longest increasing subsequence is the largest value among the
LIS(i) values.

int ans = 0, pos = 0;

for (int i = 1; i <= n; i++){


if (ans < mem[i]){
ans = mem[i];
pos = i;
}
}
cout << ans << endl;

24
The longest increasing subsequence: Complexity

• There are n possibilities for input


• Each input is calculated in O(n).
• Total calculation time is O(n2)
• Can be run (within 1 second) up to n ≤ 10000, much better than the brute force method
• Applying the segment tree structure to the above method will improve the complexity to O(nlogn).
• Another improved method is to use a new dynamic programming formular that incorporates binary
search which also gives O(nlogn)
• Trace?

25
Longest increasing subsequence (LIS): improvement using binary search

• Scan the sequence A[1], A[2], . . ., A[n] from left to right


• For each index i, maintain a list L of increasing subsequences L[1], L[2], . . .L[k], of lengths 1, 2, 3,
. . ., k of the sequence A[1], A[2], . . ., A[i].
• Each increasing subsequence maintains that last element x[1], x[2], . . ., x[k] which are the
smallest possible (we have the property: x[1] < x[2] < . . . < x[k])
• When moving from index i to index i+1, we update L as follows:
• Perform the binary search on x[1], x[2], . . ., x[k] to find the index j of the smallest element
which is greater or equal to A[i+1] (can use the lower_bound(.) function of C++)
• If no index found, then create new list L[k+1] by adding A[i+1] at the end of L[k], add L[k+1]
at the end of L
• Otherwise, update x[j] = A[i+1]

26
Longest increasing subsequence (LIS): improvement using binary search
• Example A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1]
• i = 1: A[1] = 4 → L[1] = [4]
• i = 2: A[2] = 2 → L[1] = [2]
• i = 3: A[3] = 6 → L[1] = [2], L[2] = [2, 6]
• i = 4: A[4] = 3 → L[1] = [2], L[2] = [2, 3] (replace [2,6] by [2,3] in which 3 is smaller than 6)
• i = 5: A[5] = 8 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 8] (create new list L[3] by adding 8 at the end
of L[2]
• i = 6: A[6] = 4 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4] (replace [2, 3, 8] by [2, 3, 4] in which 4 is
smaller than 8)
• i = 7: A[7] = 5 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5] (create new list L[4])
• i = 8: A[8] = 9 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5], L[5] = [2, 3, 4, 5, 9]
• i = 9: A[9] = 6 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5], L[5] = [2, 3, 4, 5, 6]
• i = 10: A[10] = 1 → L[1] = [1], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5], L[5] = [2, 3, 4, 5, 6]

27
Longest increasing subsequence (LIS): improvement using binary search
#include <bits/stdc++.h> int main(){
using namespace std; input();
vector<int> A; for(int i = 0; i< n; i++){
int n; vector<int>::iterator p =
vector<int> x; lower_bound(x.begin(), x.end(), A[i]);
void input(){ int lb = p - x.begin();
scanf("%d",&n); if(lb == x.size()){ x.push_back(A[i]); }
for(int i = 0; i< n; i++){ else{ x[lb] = A[i]; }
int v; scanf("%d",&v); A.push_back(v); }
} int res = x.size();
} cout << res;
return 0;
}

28
Longest increasing subsequence (LIS): improvement using segment trees

• Sort the sequence in non-decreasing order of values, maintain indices of the elements in the original
sequence:
• index[i] is the index of element A[i] in the sorted sequence
• If two elements A[i] = A[j] with i < j, then A[i] is located after A[j] in the sorted sequence: index[i] >
index[j]

29
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1]

1 2 3 4 5 6 7 8 9 10
4 2 6 3 8 4 5 9 6 1

Sort
1 2 3 4 5 6 7 8 9 10
A 4 2 6 3 8 4 5 9 6 1
1 2 3 4 4 5 6 6 8 9 index 5 2 8 3 9 4 6 10 7 1

• Scan the original sequence from left to right, for each index i:
• compute the length LIS[i] of the longest increasing subsequence of A[1], A[2], . . ., A[i]:
• LIS[i] = result[index[i]] = max(result[1],. . ., result[index[i] – 1]) + 1
• Use a segment tree to query max(result[1],. . ., result[index[i] – 1])

30
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 1: index[1] = 5, LIS[1] = result[5] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..4] + 1) = 1 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 0 0 0 1 0 0 0 0 0

31
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 2: index[2] = 2, LIS[2] = result[2] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..1] + 1) = 1 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 0 0 1 0 0 0 0 0

32
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 3: index[3] = 8, LIS[3] = result[8] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..7] + 1) = 2 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 0 0 1 0 0 2 0 0

33
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 4: index[4] = 3, LIS[4] = result[3] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..2] + 1) = 2 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 0 1 0 0 2 0 0

34
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 5: index[5] = 9, LIS[5] = result[9] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..8] + 1) = 3 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 0 1 0 0 2 3 0

35
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 6: index[6] = 4, LIS[6] = result[4] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..3] + 1) = 3 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 0 0 2 3 0

36
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 7: index[7] = 6, LIS[7] = result[6] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..5] + 1) = 4 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 4 0 2 3 0

37
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 8: index[8] = 10, LIS[8] = result[10] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..9] + 1) = 5 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 4 0 2 3 5

38
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 9: index[9] = 7, LIS[9] = result[7] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..6] + 1) = 5 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 4 5 2 3 5

39
Longest increasing subsequence (LIS): improvement using segment trees

• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 10: index[10] = 1, LIS[10] = result[1] = A 4 2 6 3 8 4 5 9 6 1
max(result[0..0] + 1) = 1 index 5 2 8 3 9 4 6 10 7 1

1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 1 1 2 3 1 4 5 2 3 5

40
Longest increasing subsequence (LIS): Tracing using recursion

void Trace(int i) {
for (int j = 1; j < i; j++){
if (a[j] < a[i] && mem[i] == 1 + mem[j]){
Trace(j);
break;
}
}
cout << a[i] << ' ';
}

• Call Trace(pos);
• The complexity of Trace function? O(n2)
• Can be improved: O(n)

41
Longest increasing subsequence (LIS): Tracing using recursion (improved)

void Trace(int i) {
for (int j = i - 1; j >= 1; j--){
if (a[j] < a[i] && mem[i] == 1 + mem[j]){
Trace(j);
break;
}
}
cout << a[i] << ' ';
}

• Call Trace(pos);
• The complexity of Trace function? O(n)

42
Longest increasing subsequence (LIS): Tracing using loop
stack<int> stk;
int i = pos;

for (int k = 0; k < ans; k++) {


stk.push(i);
for(int j = i - 1; j >= 1; j--) {
if (a[j] < a[i] && mem[i] == 1 + mem[j]) {
i = j;
break;
}
}

while (!stk.empty()) {
cout << stk.top() << ' ';
stk.pop();
}
}
43
CONTENTS

• Introduction to dynamic programming


• Fibonacci numbers
• Money change
• The longest ascending subsequence (Dãy con tăng dài nhất)
• Longest common subsequence (Dãy con chung dài nhất)
• Dynamic Programming with Bitmasking (TSP)

44
Longest common subsequence (Dãy con chung dài nhất)

• Given two strings (or two integer arrays) of n and m elements X[1], X[2], ..., X[n] và
Y[1], Y[2],..., Y[m]. Find the length of the longest common subsequence of the two
strings.
• Example: X = "abcb", Y = "bdcab"
• The longest common subsequence of X and Y is là "bcb" which has the length 3.

45
Longest common subsequence: Dynamic programming formular

• Let LCS(i, j) be the length of the longest common subsequence of the sequences
X[1], X[2], ..., X[i] and Y[1], Y[2], ..., Y[j].
• Basic step:
L(0, j) = L(i, 0) = 0
• Inductive step:

46
Longest common subsequence: Implement

const int N = 1e4 + 5;


string X, Y;
int mem[N][N];
memset(mem, -1, sizeof(mem));

int LCS(int i, int j) {


if (i == 0 || j == 0) return 0;
if (mem[i][j] != -1) return mem[i][j];
int res = 0;
res = max(res, LCS(i - 1, j));
res = max(res, LCS(i, j - 1));
if (X[i-1] == Y[j-1]) {
res = max(res, 1 + LCS(i - 1, j - 1));
}
return mem[i][j] = res;
}
47
Longest common subsequence: Example

48
Longest common subsequence: Complexity

• There are n x m possibilities for input


• Each input is calculated in O(1).
• Total calculation time is O(n x m)
• How to know exactly which elements belong to the longest common
subsequence?

49
Longest common subsequence: Tracing by using recursion
void Trace(int i, int j) {
if (i == 0 || j == 0) return;
if (X[i-1] == Y[j-1] && mem[i][j] == 1 + mem[i-1][j-1]) {
Trace(i - 1, j - 1);
cout << X[i-1];
return;
}
if (mem[i][j] == mem[i-1][j]) {
Trace(i - 1, j);
return;
}
if (mem[i][j] == mem[i][j-1]) {
Trace(i, j - 1);
return;
}
}

50
Longest common subsequence: Tracing by using recursion

• The complexity of Trace function? O(n + m)

51
Longest common subsequence: Tracing by using loop
void IterTrace() {
int i = X.size(), j = Y.size();
stack<int> stk;
int ans = LCS(i, j);
for (int k = 0; k < ans; k++) {
if (X[i - 1] == Y[j - 1] && mem[i][j] == 1 + mem[i-1][j-1]) {
stk.push(X[i - 1]); i--; j--; continue;
}
if (mem[i][j] == mem[i-1][j]) {
i--; continue;
}
if(mem[i][j] == mem[i][j-1]) {
j--; continue;
}
}
while (!stk.empty()){
cout << stk.top() << ' ';
stk.pop();
}
}

52
CONTENTS

• Introduction to dynamic programming


• Fibonacci numbers
• Money change
• The longest increasing subsequence (Dãy con tăng dài nhất)
• Longest common subsequence (Dãy con chung dài nhất)
• Dynamic Programming with Bitmasking (TSP)

53
Bitmask

• Do you remember the bitmask representation for subsets?


• Each subset of a set of n elements is represented by an integer in the range 0, 1, ...,
2n – 1
• This can help implement dynamic programming methods easily on subsets

54
Traveling salesman problem

• “The history and evolution of solutions to the Traveling Salesman Problem can provide
us with some valuable concepts for business analytics and algorithm development”
• ”Just as the traveling salesman makes his journey, new analytical requirements arise
that require a journey into the development of solutions for them. As the data science
and business analytics landscape evolves with new solutions, we can learn from the
history of these journeys and apply the same concepts to our ongoing development”

55
Traveling salesman problem

• Given a graph of n vertices {0, 1, ..., n – 1} and the weight value Ci,j on each pair of
vertices i, j. Find a cycle that goes through all the vertices of the graph, each vertex
exactly once, so that the sum of the weights on that cycle is minimum.

56
Traveling salesman problem: Dynamic programming

• Without loss of generality, assume the cycle begins and ends at vertex 0.
• Let TSP(i, S) be the shortest route starting from vertex i, visiting all vertices in S and returning to
vertex 0.
• Base case: TSP(i, {}) = Ci,0
• Recurrence relation:
• TSP(i, S) = minjS{ Ci,j + TSP(j, S \ {j})}
• Solution to the original problem is TSP(0, {1, 2, . . ., n-1})
j

i . . . 0

S
57
Traveling salesman problem: Dynamic programming

• Bitmasking:
• A subset of {0, 1, 2, . . ., n-1} is represented by a sequence of bits bit bn-1bn-2…b0
• bi = 1 means that i belongs to the subset, and bi = 0 means that i does not belong to the subset
• The sequence bn-1bn-2…b0 is represented by a non-negative integer N
• Perform bit manipulation on N to reflect the corresponding set operations: insertion,
removal, existence checking
unsigned int removeItem(unsigned int S, int i){ bool contains(unsigned int S, int i){
return S ^ (1 << i); if(((S >> i) & 1) > 0)
} return true;
unsigned int addItem(unsigned int S, int i){ else return false;
return S | (1 << i); }
}

58
Traveling salesman problem: Dynamic programming

int main(){ int TSP(int i, unsigned int S){


scanf("%d",&n); if(S == 0){ M[i][S] = d[i][0]; return M[i][S]; }
for(int i = 0; i <= n-1; i++) if(M[i][S] == -1){// subproblem not solved
for(int j = 0; j <= n-1; j++) M[i][S] = 100000000;
scanf("%d",&d[i][j]); for(int j = 0; j <= n-1; j++){
unsigned int S = 0; if(contains(S,j)){
for(int i = 1; i <= n-1; i++) int A = TSP(j,removeItem(S,j));
S = addItem(S,i); if(M[i][S] > d[i][j] + A){ M[i][S] = d[i][j] + A; }
for(int i = 0; i < 32; i++) }
for(int j = 0; j < N; j++) }
M[i][j] = -1; }
cout << TSP(0,S); return M[i][S];
} }

59
THANK YOU !

60

You might also like