Tải bản đầy đủ (.docx) (41 trang)

Đề giải 26 câu của Nhập Môn Thuật Toán của Trường Đại Học Quy Nhơn

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (125.21 KB, 41 trang )

Câu hỏi phương pháp:
1. Trình bày phương pháp Chia để trị trong thiết kế thuật toán
Phương pháp "Chia để trị" (Divide and Conquer) là một phương pháp thiết kế thuật
toán phổ biến được sử dụng để giải quyết các bài toán phức tạp bằng cách chia
chúng thành các bài toán con nhỏ hơn, giải quyết các bài tốn con đó một cách đệ
quy, và kết hợp kết quả để tạo ra kết quả cuối cùng.

2. Trình bày phương pháp Quy hoạch động trong thiết kế thuật
toán
Phương pháp Quy hoạch động (Dynamic Programming) là một phương pháp thiết kế
thuật toán mạnh mẽ được sử dụng để giải quyết các bài toán tối ưu hóa. Phương
pháp này thường được áp dụng cho các bài tốn có cấu trúc đệ quy, trong đó ta có
thể chia bài tốn thành các bài tốn con nhỏ hơn và lưu trữ kết quả của các bài tốn
con đó để sử dụng lại trong q trình giải quyết bài tốn gốc.

3. Trình bày phương pháp Tham lam trong thiết kế thuật toán
Là phương pháp được sử dụng để giải quyết các bài tốn tối ưu
như tìm một trình tự tốt nhất thực hiện cơng việc , tìm đường đi
ngắn nhất trên đồ thị, v.v

**Bài tập minh hoạ cho phương pháp


Câu 1: Cho 1 ví dụ minh hoạ thiết kế thuật toán bằng phương
pháp Chia để trị bao gồm: bài tốn, áp dụng phương pháp, thuật
tốn giải.
Bài tốn: Tìm kiếm phần tử trong một mảng đã được sắp
xếp tăng dần.
Áp dụng phương pháp Chia để trị:
1. Bước Chia: Chia mảng thành hai nửa (hoặc nhiều phần) tại
một chỉ mục trung tâm. Ta so sánh phần tử tại chỉ mục trung


tâm với giá trị cần tìm. Nếu phần tử trung tâm lớn hơn giá trị
cần tìm, ta chia mảng thành nửa bên trái của phần tử trung
tâm, ngược lại, ta chia mảng thành nửa bên phải của phần tử
trung tâm.
2. Bước Trị: Đệ quy tìm kiếm trong nửa mảng đã chia.
3. Bước Kết hợp: Trả về kết quả tìm kiếm từ các phần tử con đã
tìm kiếm được.
Thuật tốn giải:
Tong(arr, n, m, t):
if n > m:
return -1 # Khơng tìm thấy mục tiêu trong mảng
i = (n + m) // 2
if arr[i] = = t: #Nếu tập hợp của i = t
return i # Phần tử được tìm thấy
else if arr[i] > t: Nếu tập hợp của i > t
return Tong(arr, n, i - 1, t) # Tìm trong nửa bên trái của
mảng
else:
return Tong(arr, i + 1, m, t) # Tìm trong nửa bên phải của
mảng


Câu 2: Cho dãy số a = (5, 8, 1, 4, 9, 7, 4, 2, 5, 6). Hãy trình bày
các bước áp dụng thuật toán sắp xếp trộn để sắp dãy a theo thứ
tự tăng. Cho biết phương pháp Chia để trị áp dụng cho thuật toán
này ở những điểm nào?
Bước Chia:
Chia dãy số a thành hai nửa bằng cách tìm chỉ mục trung tâm mid
= (low + high) / 2, trong đó low là chỉ mục đầu tiên của dãy và
high là chỉ mục cuối cùng của dãy.

a = (5, 8, 1, 4, 9) | (7, 4, 2, 5, 6)
Đệ quy chia các nửa dãy con tiếp tục cho đến khi không thể chia
nhỏ hơn.
a = (5) | (8, 1, 4, 9) | (7) | (4, 2, 5, 6)
Tiếp tục chia các nửa con còn lại.
a = (5) | (8) | (1, 4, 9) | (7) | (4) | (2, 5, 6)
Bước Kết hợp:
4. Trộn các nửa con lại với nhau theo thứ tự tăng dần để tạo ra
dãy con đã sắp xếp.
a = (5, 8) | (1, 4, 9) | (4, 7) | (2, 5, 6)
Tiếp tục trộn các dãy con cho đến khi thu được dãy số đã sắp xếp.
a = (1, 4, 5, 8, 9) | (2, 4, 5, 6, 7)
Trộn hai dãy đã sắp xếp lại với nhau để thu được dãy a đã được
sắp xếp theo thứ tự tăng dần.
a = (1, 2, 4, 4, 5, 5, 6, 7, 8, 9)
Phương pháp Chia để trị được áp dụng trong Bước Chia khi ta chia
dãy số thành các nửa con, và trong Bước Kết hợp khi ta trộn các
dãy con lại với nhau theo thứ tự tăng dần.

Câu 3: Cho dãy số a = (5, 8, 1, 4, 9, 7, 4, 2, 5, 6). Hãy trình bày
các bước áp dụng thuật tốn Quick Sort để sắp dãy a theo thứ tự


tăng. Cho biết phương pháp Chia để trị áp dụng cho thuật toán
này ở những điểm nào?
Dãy số a = (5, 8, 1, 4, 9, 7, 4, 2, 5, 6)
Bước Chia:
Chọn một phần tử làm phần tử chốt (pivot). Trong ví dụ này, chọn
phần tử cuối cùng của dãy làm pivot.
a = (5, 8, 1, 4, 9, 7, 4, 2, 5, 6) | Pivot = 6

Chia dãy số thành hai phần, một phần chứa các phần tử nhỏ hơn
hoặc bằng pivot và một phần chứa các phần tử lớn hơn pivot. Sử
dụng kỹ thuật "Partitioning".
a = (5, 1, 4, 4, 2, 5) | Pivot = 6 | (8, 9, 7)
Đệ quy áp dụng thuật toán Quick Sort cho cả hai phần con đã
chia.
a = (1, 4, 4, 2, 5) | Pivot = 5 | (5, 6)
a = (1, 4, 4, 2) | Pivot = 2 | (5)
a = (1, 4, 4) | Pivot = 4 | ()
a = (1, 4) | Pivot = 4 | ()
a = (1) | Pivot = 1 | (4)
Bước Kết hợp:
4. Kết hợp các phần tử đã được sắp xếp lại với nhau để tạo ra dãy
đã sắp xếp.
a = (1, 4) | (1, 4) | (1, 2, 4) | (1, 2, 4, 5) | (5, 6, 8, 9)
5. Dãy a đã được sắp xếp theo thứ tự tăng dần.
Phương pháp Chia để trị trong thuật tốn Quick Sort được áp dụng
trong q trình chia dãy số thành các phần tử con, tìm pivot và áp
dụng đệ quy cho các phần tử con.


Câu 4: Cho dãy số đã sắp tăng a = (1, 5, 9, 14, 19, 27, 34, 42, 55,
66). Hãy trình bày các bước áp dụng thuật tốn tìm nhị phân để
tìm số 55 có trong dãy a khơng?. Cho biết phương pháp Chia để
trị áp dụng cho thuật toán này ở những điểm nào?
Dãy số đã sắp tăng a = (1, 5, 9, 14, 19, 27, 34, 42, 55, 66)
Bước 1:
Đặt low = 0 và high = độ dài của dãy - 1
low = 0, high = 9
Bước 2:

Tìm chỉ mục trung tâm mid = (low + high) / 2
mid = (0 + 9) / 2 = 4
Bước 3:
So sánh phần tử ở vị trí mid với số cần tìm (55).
a[mid] = 19 < 55
Bước 4:
Vì a[mid] < 55, nên số cần tìm có thể nằm trong nửa bên phải của
dãy.
Đặt low = mid + 1
low = 5, high = 9
Bước 5:
Tìm lại chỉ mục trung tâm mới.
mid = (5 + 9) / 2 = 7
Bước 6:
So sánh phần tử ở vị trí mid với số cần tìm (55).
a[mid] = 42 < 55
Bước 7:


Vì a[mid] < 55, nên số cần tìm có thể nằm trong nửa bên phải của
dãy.
Đặt low = mid + 1
low = 8, high = 9
Bước 8:
Tìm lại chỉ mục trung tâm mới.
mid = (8 + 9) / 2 = 8
Bước 9:
So sánh phần tử ở vị trí mid với số cần tìm (55).
a[mid] = 55
Bước 10:

Phần tử ở vị trí mid trùng khớp với số cần tìm (55). Tìm kiếm kết
thúc.
Số 55 có trong dãy a.
Phương pháp Chia để trị khơng được áp dụng trong thuật tốn tìm
nhị phân. Trong thuật toán này, ta tiến hành chia mảng thành các
nửa và tìm kiếm dựa trên việc so sánh phần tử ở giữa mảng với số
cần tìm để xác định nửa mảng tiếp theo cần xem xét. Quá trình
này tiếp tục cho đến khi tìm thấy phần tử hoặc xác định rằng
phần tử khơng có trong mảng.

Câu 5: Cho dãy a = (2, -15, 6, 2, 9, -4, 7, 3, -5, 2), trình bày các
bước tìm đoạn con có tổng lớn nhất của dãy a bằng thuật toán
chia để trị. Cho biết phương pháp chia để trị áp dụng cho thuật
toán này ở những điểm nào?
Bước 1:
Đặt hai biến max_so_far và max_ending_here bằng giá trị của
phần tử đầu tiên trong dãy.
max_a = 2


max_b = 2
Bước 2:
Duyệt qua các phần tử từ phần tử thứ 2 đến phần tử cuối của dãy.
- Với mỗi phần tử, cập nhật max_b bằng tổng của max_b hiện tại
và phần tử đó.
- Nếu max_b âm hơn 0, gán max_b = 0 (bắt đầu tính lại tổng từ
phần tử tiếp theo).
- So sánh max_a hiện tại với max_b và cập nhật max_a nếu cần.
Các bước cụ thể như sau:
2: max_b = 2, max_a= 2 (max_so_far không thay đổi)

-15: max_b = max_b + (-15) = -13, max_a = 2 (max_a không thay
đổi)
6: max_b = max_b + 6 = -7, max_a = 2 (max_a không thay đổi)
2: max_b = max_b + 2 = -5, max_a = 2 (max_a không thay đổi)
9: max_b = max_b + 9 = 4, max_a = 4 (max_a được cập nhật)
-4: max_b = max_b + (-4) = 0, max_a = 4 (max_a không thay đổi)
7: max_b = max_b + 7 = 7, max_a = 7 (max_a được cập nhật)
3: max_b = max_b + 3 = 10, max_a = 10 (max_a được cập nhật)
-5: max_b = max_b + (-5) = 5, max_a = 10 (max_a không thay
đổi)
2: max_b = max_b + 2 = 7, max_a = 10 (max_a không thay đổi)
Bước 3:
Kết quả cuối cùng là giá trị của max_so_far là 10.
Đoạn con có tổng lớn nhất trong dãy a là (7, 3).
Trong thuật toán Kadane, phương pháp chia để trị không được áp
dụng trực tiếp trong việc tìm đoạn con có tổng lớn nhất. Thay vào


đó, thuật tốn Kadane sử dụng một phương pháp tận dụng tính
chất tích lũy của các đoạn con để tìm đoạn con có tổng lớn nhất.
Cụ thể, thuật tốn Kadane tại mỗi bước duyệt qua phần tử trong
dãy, nó tính tổng lũy kế (max_ending_here) của đoạn con kết thúc
tại phần tử hiện tại và so sánh với tổng lớn nhất đã biết
(max_so_far). Nếu tổng lũy kế lớn hơn tổng lớn nhất đã biết, thì
tổng lớn nhất được cập nhật. Nếu tổng lũy kế âm hơn 0, thì tổng
lũy kế được thiết lập về 0 và bắt đầu tính tổng mới từ phần tử tiếp
theo.
Phương pháp chia để trị không được áp dụng trực tiếp trong thuật
toán Kadane, mà thuật toán Kadane tận dụng tính chất tích lũy
của đoạn con để tìm tổng lớn nhất.


Câu 6: Cho dãy a = (2, -15, 6, 2, -9, -4, 7, 3, -5, 2), trình bày các
bước tìm đoạn con có tổng nhỏ nhất của dãy a bằng thuật toán
chia để trị. Cho biết phương pháp chia để trị áp dụng cho thuật
toán này ở những điểm nào?
Chia dãy thành hai phần bằng nhau:
Chọn chỉ số trung điểm mid = (low + high) / 2, với low là chỉ số
bắt đầu và high là chỉ số kết thúc của dãy con cần xét.
Gọi đệ quy để tìm đoạn con có tổng nhỏ nhất của dãy bên trái, từ
low đến mid: findMinSubarray(arr, low, mid).
Gọi đệ quy để tìm đoạn con có tổng nhỏ nhất của dãy bên phải, từ
mid+1 đến high: findMinSubarray(arr, mid+1, high).
Tìm đoạn con có tổng nhỏ nhất chứa điểm trung điểm:
Tính tổng từ mid đến low (từ trái sang phải) và gán cho sumLeft.
Tính tổng từ mid+1 đến high (từ phải sang trái) và gán cho
sumRight.
Tìm tổng nhỏ nhất của các đoạn con:
So sánh sumLeft và sumRight, chọn tổng nhỏ nhất.


So sánh tổng nhỏ nhất vừa tìm được với tổng nhỏ nhất của đoạn
con bên trái và đoạn con bên phải đã được tìm ở bước 1.
Trả về tổng nhỏ nhất của các đoạn con.

Câu 7: Trình bày thuật tốn tìm nhị phân dùng để tìm một phần
tử trong mảng đã sắp xếp. Cho biết phương pháp Chia để trị áp
dụng cho thuật toán này ở những điểm nào?
Dưới đây là trình bày thuật tốn tìm kiếm nhị phân và phương
pháp chia để trị áp dụng cho thuật toán này:
Khởi tạo biến low = 0 (chỉ số đầu mảng) và high = n - 1 (chỉ số

cuối mảng), với n là kích thước mảng.
Lặp lại cho đến khi low <= high:
Tìm chỉ số trung điểm mid = (low + high) / 2.
So sánh phần tử tại chỉ số mid với phần tử cần tìm:
Nếu phần tử tại chỉ số mid bằng phần tử cần tìm, trả về mid.
Nếu phần tử tại chỉ số mid lớn hơn phần tử cần tìm, cập nhật high
= mid - 1.
Nếu phần tử tại chỉ số mid nhỏ hơn phần tử cần tìm, cập nhật low
= mid + 1.
Nếu khơng tìm thấy phần tử trong mảng, trả về -1 hoặc giá trị
tượng trưng cho không tìm thấy.
Phương pháp chia để trị được áp dụng ở bước chia mảng thành hai
nửa phía trước và phía sau dựa trên giá trị của phần tử trung điểm
(mid). Điều này giúp thuật tốn tìm kiếm nhị phân giảm đáng kể
kích thước của mảng con cần xét ở mỗi bước, từ đó tăng hiệu quả
của thuật tốn.


Câu 8: Trình bày thuật tốn tìm số lớn nhất trong một mảng bằng
phương pháp Chia để trị.
Được thực hiện bằng các bước sau :
1. Chia mảng ban đầu thành hai phần bằng cách tìm chỉ số
trung tâm:
B1: tìm chỉ số trung tâm : mid = (low + high) / 2
B2: chia mảng thành 2 mảng con :
left_array = array[low:mid]
right_array = array[mid+1:high]
2. Gọi hàm đệ quy để tìm số lớn nhất trong 2 mảng con :
left_array: left_max = find_max(left_array)
right_array: right_max = find_max(right_array)

3. So sánh và trả về số lớn nhất giữa left_max và right_max:
Nếu left_max > right_max, trả về left_max là số lớn nhất
Ngược lại, trả về right_max là số lớn nhất
Thuật tốn này sử dụng tính chất đệ quy của Chia để trị để chia
nhỏ bài toán thành các bài tốn con nhỏ hơn và sau đó kết hợp
kết quả từ các bài toán con để đưa ra kết quả cuối cùng. Trong
trường hợp này, chúng ta chia mảng ban đầu thành các mảng con
nhỏ hơn, tìm số lớn nhất trong từng mảng con và sau đó so sánh
kết quả để tìm ra số lớn nhất trong tồn bộ mảng.

Câu 9: Cho trước một dãy số nguyên a có n phần tử và một phần
tử có giá trị là x, hãy mơ tả thuật tốn chia để trị để đếm số lần
phần tử x xuất hiện trong dãy a (có thể x khơng xuất hiện trong
dãy a). Hãy mơ tả thuật tốn chia để trị để tính số lần xuất hiện
của phần tử x = 2 trong dãy số a = 2, 15, 6, 2, 9, 4, 7, 3, 5, 2
Cách làm :


Chia mảng ban đầu thành hai phần bằng cách tìm chỉ số trung
tâm:
Tìm chỉ số trung tâm: mid = (low + high) / 2
Chia mảng thành hai mảng con:
left_array = array[low:mid] và right_array = array[mid+1:high]
Gọi đệ quy để tìm số lớn nhất trong hai mảng con:
Gọi hàm đệ quy để tìm số lớn nhất trong left_array:
left_max = find_max(left_array)
Gọi hàm đệ quy để tìm số lớn nhất trong right_array:
right_max = find_max(right_array)
So sánh và trả về số lớn nhất giữa left_max và right_max:
Nếu left_max > right_max, trả về left_max là số lớn nhất

Ngược lại, trả về right_max là số lớn nhất
Thuật toán này sử dụng tính chất đệ quy của Chia để trị để chia
nhỏ bài toán thành các bài toán con nhỏ hơn và sau đó kết hợp
kết quả từ các bài toán con để đưa ra kết quả cuối cùng. Trong
trường hợp này, chúng ta chia mảng ban đầu thành các mảng con
nhỏ hơn, tìm số lớn nhất trong từng mảng con và sau đó so sánh
kết quả để tìm ra số lớn nhất trong tồn bộ mảng.
Mơ tả thuật toán bằng C++ :
int countOccurrences(vector<int>& array, int x) {
int n = array.size();
// Trường hợp cơ sở: Mảng rỗng
if (n == 0) {
return 0;
}
// Trường hợp cơ sở: Mảng chỉ có một phần tử


if (n == 1) {
if (array[0] == x) {
return 1;
} else {
return 0;
}
}
// Chia mảng thành hai phần
int mid = n / 2;
vector<int> left_array(array.begin(), array.begin() + mid);
vector<int> right_array(array.begin() + mid, array.end());
// Đệ quy để đếm số lần xuất hiện của x trong hai mảng con
int left_count = countOccurrences(left_array, x);

int right_count = countOccurrences(right_array, x);
// Tính số lần xuất hiện của x trong đoạn con nằm giữa
left_array và right_array
int between_count = 0;
int left_end = left_array.size() - 1;
int right_start = 0;
while (left_end >= 0 && left_array[left_end] == x) {
between_count++;
left_end--;
}


while (right_start < right_array.size() && right_array[right_start]
== x) {
between_count++;
right_start++;
}
// Tổng số lần xuất hiện của x
return left_count + right_count + between_count;
}
Mô tả thuật toán bằng Python :
def count_occurrences(array, x):
n = len(array)
# Base case: Trường hợp mảng rỗng
if n == 0:
return 0
# Base case: Trường hợp mảng chỉ có một phần tử
if n == 1:
if array[0] == x:
return 1

else:
return 0
# Chia mảng thành hai phần
mid = n // 2
left_array = array[:mid]
right_array = array[mid:]


# Đệ quy để đếm số lần xuất hiện của x trong hai mảng con
left_count = count_occurrences(left_array, x)
right_count = count_occurrences(right_array, x)
# Tính số lần xuất hiện của x trong đoạn con nằm giữa
left_array và right_array
between_count = 0
left_end = len(left_array) - 1
right_start = 0
while left_end >= 0 and left_array[left_end] == x:
between_count += 1
left_end -= 1
while right_start < len(right_array) and right_array[right_start]
== x:
between_count += 1
right_start += 1
# Tổng số lần xuất hiện của x
return left_count + right_count + between_count
# Dãy số và phần tử cần tìm
a = [2, 15, 6, 2, 9, 4, 7, 3, 5, 2]
x=2
# Gọi hàm để tính số lần xuất hiện của x trong dãy a
occurrences = count_occurrences(a, x)

# In kết quả
print("Số lần xuất hiện của", x, "trong dãy a là:", occurrences)


Câu 10: Cho 1 ví dụ minh hoạ thiết kế thuật toán bằng phương
pháp Quy hoạch động bao gồm: bài toán, áp dụng phương pháp,
thuật toán giải
Áp dụng phương pháp Quy hoạch động:
Đặt dp[i] là độ dài của dãy con tăng dài nhất kết thúc tại vị trí i
trong dãy số.
Với mỗi vị trí i trong dãy số, ta cần kiểm tra các vị trí trước đó (từ
0 đến i-1) và xem xét xem có thể thêm phần tử arr[i] vào dãy con
tăng hiện tại để tạo thành một dãy con tăng dài hơn hay khơng.
Trong q trình kiểm tra, ta cần duyệt qua tất cả các vị trí j (từ 0
đến i-1) và nếu arr[i] > arr[j], ta cập nhật dp[i] = max(dp[i], dp[j]
+ 1). Điều này có nghĩa là ta cập nhật độ dài của dãy con tăng kết
thúc tại vị trí i bằng giá trị lớn nhất trong các độ dài của dãy con
tăng kết thúc tại các vị trí j mà arr[j] nhỏ hơn arr[i], sau đó tăng
độ dài này thêm 1.
Cuối cùng, để tìm độ dài của dãy con tăng dài nhất trong dãy số
ban đầu, ta tìm giá trị lớn nhất trong mảng dp và đó chính là độ
dài cần tìm.
Thuật tốn giải:
Khởi tạo mảng dp có cùng độ dài với dãy số ban đầu, tất cả các
phần tử trong dp ban đầu được đặt bằng 1.
Duyệt qua từng vị trí i trong dãy số:
Duyệt qua tất cả các vị trí j từ 0 đến i-1:
Nếu arr[i] > arr[j], cập nhật dp[i] = max(dp[i], dp[j] + 1).
Tìm giá trị lớn nhất trong mảng dp và trả về kết quả.
Thuật toán giải:

Khởi tạo mảng dp có cùng độ dài với dãy số ban đầu, tất cả các
phần tử trong dp ban đầu được đặt bằng 1.
Duyệt qua từng vị trí i trong dãy số:
Duyệt qua tất cả các vị trí j từ 0 đến i-1:


Nếu arr[i] > arr[j], cập nhật dp[i] = max(dp[i], dp[j] + 1).
Tìm giá trị lớn nhất trong mảng dp và trả về kết quả.
Ví dụ minh hoạ:
Giả sử chúng ta có dãy số arr = {3, 1, 5, 2, 4, 9, 6, 8}.
Bước 1: Khởi tạo mảng dp với cùng độ dài và tất cả các phần tử
đều bằng 1:
dp = {1, 1, 1, 1, 1, 1, 1, 1}
Bước 2: Duyệt qua từng vị trí i trong dãy số:
Với i = 0:
Khơng có vị trí j nào nhỏ hơn 0 để kiểm tra, do đó khơng có gì để
cập nhật.
Với i = 1:
Khơng có vị trí j nào nhỏ hơn 1 để kiểm tra, do đó khơng có gì để
cập nhật.
Với i = 2:
Có một vị trí j = 0 thỏa mãn arr[2] > arr[0], nên cập nhật dp[2] =
max(dp[2], dp[0] + 1) = max(1, 1 + 1) = 2.
Với i = 3:
Có hai vị trí j = 0 và j = 2 thỏa mãn arr[3] > arr[0] và arr[3] >
arr[2], nên cập nhật dp[3] = max(dp[3], dp[0] + 1, dp[2] + 1) =
max(1, 1 + 1, 2 + 1) = 3.
Với i = 4:
Có hai vị trí j = 0 và j = 2 thỏa mãn arr[4] > arr[0] và arr[4] >
arr[2], nên cập nhật dp[4] = max(dp[4], dp[0] + 1, dp[2] + 1) =

max(1, 1 + 1, 2 + 1) = 3.
Với i = 5:


Có năm vị trí j = 0, j = 1, j = 2, j = 3, và j = 4 thỏa mãn arr[5] >
arr[0], arr[5] > arr[1], arr[5] > arr[2], arr[5] > arr[3], và arr[5] >
arr[4], nên cập nhật dp[5] = max(dp[5], dp[0] + 1, dp[1] + 1,
dp[2] + 1, dp[3] + 1, dp[4] + 1) = max(1, 1 + 1, 2 + 1, 3 + 1, 3 +
1) = 4.
Với i = 6:
Có hai vị trí j = 2 và j = 5 thỏa mãn arr[6] > arr[2] và arr[6] >
arr[5], nên cập nhật dp[6] = max(dp[6], dp[2] + 1, dp[5] + 1) =
max(1, 2 + 1, 4 + 1) = 5.
Với i = 7:
Có hai vị trí j = 2 và j = 5 thỏa mãn arr[7] > arr[2] và arr[7] >
arr[5], nên cập nhật dp[7] = max(dp[7], dp[2] + 1, dp[5] + 1) =
max(1, 2 + 1, 4 + 1) = 5.
Bước 3: Tìm giá trị lớn nhất trong mảng dp:
dp = {1, 1, 2, 3, 3, 4, 5, 5}
Giá trị lớn nhất là 5, chính là độ dài của dãy con tăng dài nhất
trong dãy số ban đầu.
Vậy, dãy con tăng dài nhất trong dãy số arr = {3, 1, 5, 2, 4, 9, 6,
8} có độ dài là 5.

Câu 11.Trình bày thuật tốn quy hoạch động tìm số Fibonaci thứ
n. Cho biết phương pháp quy hoạch động áp dụng cho thuật toán
này ở những điểm nào?
Thuật tốn Quy hoạch động có thể được áp dụng để tính số
Fibonacci thứ n. Phương pháp Quy hoạch động thường được sử
dụng để giảm độ phức tạp của các bài toán tổ hợp, bằng cách

chia bài toán ban đầu thành các bài toán con nhỏ hơn và lưu trữ
các kết quả trung gian để tránh tính tốn lặp lại.
Điểm quan trọng của phương pháp Quy hoạch động trong thuật
toán Fibonacci là việc lưu trữ các giá trị Fibonacci đã tính tốn
trước đó để sử dụng lại trong các bước tính tốn sau này. Bằng


cách này, ta chỉ cần tính tốn Fibonacci của các số nhỏ hơn trước
đó một lần duy nhất và sử dụng lại kết quả đó để tính tốn
Fibonacci của các số lớn hơn.
Dưới đây là một thuật toán Quy hoạch động để tính số Fibonacci
thứ n:
1. Khởi tạo một mảng fib với độ dài là n+1 và tất cả các phần
tử ban đầu đều bằng 0.
2. Gán fib[1] = 1 và fib[2] = 1.
3. Duyệt qua từng vị trí i từ 3 đến n:
4. Gán fib[i] = fib[i-1] + fib[i-2].
5. Trả về giá trị fib[n].
6. Trong thuật toán trên, ta lưu trữ các giá trị Fibonacci đã tính
tốn trước đó trong mảng fib. Các bước tính tốn tiếp theo sẽ
sử dụng các giá trị đã tính tốn trước đó để tính tốn các giá
trị Fibonacci mới. Nhờ đó, ta tránh được việc tính tốn lặp lại
các giá trị Fibonacci của các số nhỏ hơn.
Áp dụng phương pháp Quy hoạch động cho thuật toán Fibonacci
tại các điểm quan trọng:
Lưu trữ các giá trị Fibonacci đã tính tốn trước đó trong một
mảng.
Sử dụng kết quả đã tính tốn trước đó để tính tốn Fibonacci của
các số lớn hơn.
Tính tốn các giá trị Fibonacci theo thứ tự từ nhỏ đến lớn.


Câu 12: Trình bày thuật tốn quy hoạch động tính Cnk. Cho biết
phương pháp quy hoạch động áp dụng cho thuật toán này ở
những điểm nào?
Thuật tốn Quy hoạch động có thể được áp dụng để tính hệ số nhị
thức C(n, k), tức là số cách chọn k phần tử từ tập hợp n phần tử.
Phương pháp Quy hoạch động giúp giảm độ phức tạp của bài toán
bằng cách chia bài toán ban đầu thành các bài toán con nhỏ hơn
và lưu trữ các kết quả trung gian để tránh tính tốn lặp lại.


Điểm quan trọng của phương pháp Quy hoạch động trong thuật
toán C(n, k) là việc lưu trữ các giá trị đã tính tốn trước đó để sử
dụng lại trong các bước tính tốn sau này. Bằng cách này, ta chỉ
cần tính tốn các giá trị C(i, j) một lần duy nhất và sử dụng lại kết
quả đó để tính tốn các giá trị C(i', j') với i' > i và j' > j.
Dưới đây là một thuật toán Quy hoạch động để tính hệ số nhị thức
C(n, k):
1. Khởi tạo một ma trận dp có kích thước (n+1) x (k+1) và tất
cả các phần tử ban đầu đều bằng 0.
2. Đặt dp[i][j] = 1 cho mọi 0 <= i <= n và 0 <= j <= min(i, k).
3. Duyệt qua từng vị trí i từ 1 đến n và từng vị trí j từ 1 đến
min(i, k):
4. Gán dp[i][j] = dp[i-1][j-1] + dp[i-1][j].
5. Trả về giá trị dp[n][k].
6. Trong thuật toán trên, ta lưu trữ các giá trị hệ số nhị thức đã
tính tốn trước đó trong ma trận dp. Các bước tính tốn tiếp
theo sẽ sử dụng các giá trị đã tính tốn trước đó để tính tốn
các giá trị hệ số nhị thức mới. Nhờ đó, ta tránh được việc tính
tốn lặp lại các giá trị hệ số nhị thức đã được tính tốn trước

đó.
Áp dụng phương pháp Quy hoạch động cho thuật toán C(n, k) tại
các điểm quan trọng:
Lưu trữ các giá trị hệ số nhị thức đã tính tốn trước đó trong một
ma trận.
Sử dụng kết quả đã tính tốn trước đó để tính tốn các giá trị hệ
số nhị thức mới.
Tính tốn các giá trị hệ số nhị thức theo thứ tự từ nhỏ đến lớn của
n và k.

Câu 13: Trình bày thuật tốn quy hoạch động tìm dãy con tăng
dài nhất của một dãy cho trước. Cho biết phương pháp quy hoạch
động áp dụng cho thuật toán này ở những điểm nào?


Thuật tốn Quy hoạch động có thể được áp dụng để tìm dãy con
tăng dài nhất của một dãy số cho trước. Phương pháp Quy hoạch
động giúp giảm độ phức tạp của bài toán bằng cách chia bài toán
ban đầu thành các bài toán con nhỏ hơn và lưu trữ các kết quả
trung gian để tránh tính tốn lặp lại.
Điểm quan trọng của phương pháp Quy hoạch động trong thuật
toán tìm dãy con tăng dài nhất là việc lưu trữ chiều dài của dãy
con tăng dài nhất tại mỗi vị trí i. Bằng cách này, ta có thể tính
tốn chiều dài dãy con tăng dài nhất tại vị trí i dựa trên các chiều
dài đã tính tốn trước đó tại các vị trí nhỏ hơn.
Dưới đây là một thuật tốn Quy hoạch động để tìm dãy con tăng
dài nhất của một dãy số arr:
1. Khởi tạo một mảng dp có độ dài bằng độ dài của arr và tất
cả các phần tử ban đầu đều bằng 1.
2. Duyệt qua từng vị trí i trong arr từ 1 đến n-1:

3. Duyệt qua từng vị trí j từ 0 đến i-1:
4. Nếu arr[i] > arr[j], gán dp[i] = max(dp[i], dp[j] + 1).
5. Tìm giá trị lớn nhất trong mảng dp. Đây chính là chiều dài
của dãy con tăng dài nhất trong dãy số arr.
6. Trong thuật toán trên, ta lưu trữ các chiều dài của dãy con
tăng dài nhất tại mỗi vị trí i trong mảng dp. Các bước tính
tốn tiếp theo sẽ sử dụng các chiều dài đã tính tốn trước đó
để tính tốn chiều dài dãy con tăng dài nhất tại các vị trí lớn
hơn.
Áp dụng phương pháp Quy hoạch động cho thuật tốn tìm dãy
con tăng dài nhất tại các điểm quan trọng:
Lưu trữ chiều dài của dãy con tăng dài nhất tại mỗi vị trí i trong
một mảng.
Sử dụng các chiều dài đã tính tốn trước đó để tính tốn chiều dài
dãy con tăng dài nhất tại các vị trí lớn hơn.
Tính tốn chiều dài dãy con tăng dài nhất theo thứ tự từ trái sang
phải của dãy số arr.



×