Chương 3 QUY HOẠCH ĐỘNG MỤC TIÊU CỦA CHƯƠNG - Hiểu và nắm vững bản chất của phương

pháp quy hoạch động. - Cung cấp một cách tiếp cận mới trong việc giải quyết các bài toán tối ưu mang bản chất đệ quy. - Sinh viên cần nắm vững phần lý thuyết để có thể hình thành các kỹ năng trong việc tiếp cận và giải các bài toán quy hoạch động. NỘI DUNG BÀI GIẢNG LÝ THUYẾT Quy hoạch động (Dynamic programming) là một kỹ thuật nhằm đơn giản hóa việc tính toán các công thức truy hồi bằng cách lưu trữ toàn bộ hay một phần kết quả tính toán tại mỗi bước với mục đích sử dụng lại. Bản chất của quy hoạch động là nhằm thay thế mô hình tính toán “từ trên xuống” (top-down) bằng mô hình tính toán “từ dưới lên” (bottom-up). Quy hoạch động thường dùng giải các bài toán tối ưu có bản chất đệ qui • Việc tìm nghiệm tối ưu của bài toán đã cho được thực hiện dựa trên việc tìm nghiệm tối ưu của các bài toán con. • Kết quả của các bài toán con được ghi nhận lại để phục vụ cho việc giải các bài toán lớn hơn và giải được bài toán yêu cầu. 3.1. Bài toán quy hoạch Bài toán quy hoạch là bài toán tối ưu: gồm có một hàm f gọi là hàm mục tiêu hay hàm đánh giá, các hàm g1, g2, … gn cho giá trị logic gọi là hàm ràng buộc. Yêu cầu của bài toán là tìm một cấu hình x thỏa mãn tất cả các ràng buộc g1, g2, … gn: gi(x)=TRUE ( ∀ 1 ≤ i i: ≤ n) và x là tốt nhất, theo nghĩa không tồn tại một cấu hình y nào khác thỏa mãn các hàm ràng buộc mà f(y) tốt hơn f(x). Ví dụ: Tìm (x, y) để Hàm mục tiêu : x + y → max Hàm ràng buộc : x2 + y2 ≤ 1 Xét trong mặt phẳng tọa độ, những cặp (x, y) thỏa mãn x2 + y2 ≤ 1 là tọa độ của những điểm nằm trong hình tròn có tâm O là gốc tọa độ, bán kính 1. Vậy nghiệm của bài toán bắt buộc nằm trong hình tròn đó. Những đường thẳng có phương trình x + y = C (C là một hằng số) là đường thẳng vuông góc với đường phân giác góc phần tư thứ nhất. Ta phải tìm số C lớn nhất mà đường thẳng x +

1

y = C vẫn có điểm chung với đường tròn (O, 1). Đường thẳng đó là một tiếp tuyến của đường tròn : x + y = 2 . Tiếp điểm ( 1 2 , 1 2 ) tương ứng với nghiệm tối ưu của bài toán đã cho.

Các dạng bài toán quy hoạch rất phong phú và đa dạng, ứng dụng nhiều trong thực tế, nhưng cũng cần biết rằng đa số các bài toán quy hoạch là không giải được, hoặc chưa giải được. Cho đến nay người ta mới chỉ có thuật toán đơn giải giải bài toán quy hoạch tuyến tính lồi, và một vài thuật toán khác áp dụng cho bài toán cụ thể. 3.2. Phương pháp quy hoạch động Phương pháp quy hoạch động dùng để giải bài toán tối ưu có bản chất đệ quy, tức là việc tìm phương án tối ưu cho bài toán có thể đưa về tìm phương án tối ưu của số hữu hạn các bài toán con. Đối với nhiều thuật toán đệ quy chúng ta đã tìm hiểu, nguyên lý chia để trị thường đóng vai trò chủ đạo trong việc thiết kế thuật toán. Để giải quyết một bài toán lớn, ta chia nó làm nhiều bài toán con cùng dạng với nó để giải quyết độc lập. Trong phương pháp quy hoạch động, nguyên lý này càng được thể hiện rõ : Khi không biết cần phải giải quyết những bài toán con nào, ta sẽ đi giải quyết tất cả các bài toán con và lưu trữ những lời giải hay đáp số của chúng với mục đích sử dụng lại theo một sự phối hợp nào đó để giải quyết những bài toán tổng quát hơn. Đó chính là điểm khác nhau giữa quy hoạch động và phép phân giải đệ quy và cũng là nội dung của phương pháp quy hoạch động :  Phép phân giải đệ quy bắt đầu từ bài toán lớn phân rã thành nhiều bài toán con và đi giải từng bài toán con đó. Việc giải quyết từng bài toán con lại đưa về phép phân rã tiếp thành nhiều bài toán nhỏ hơn và lại đi giải tiếp bài toán nhỏ hơn đó bất kể nó đã được giải hay chưa.  Quy hoạch động bắt đầu từ việc giải tất cả các bài toán nhỏ nhất (bài toán cơ sở) để từ đó từng bước giải quyết những bài toán lớn hơn, cho tới khi giải được bài toán lớn nhất ( bài toán ban đầu). Ta xét một ví dụ đơn giản Dãy Fibonacci là dãy vô hạn các số nguyên dương F[1], F[2],…. được định nghĩa như sau :

2

 1 i ≤ 2 F[1] =   F[i − 2] + F[i − 1] i > 2 
Hãy tính F[6]

Xét hai cách cài đặt chương trình int F(int i) { if(i <=2) return 1 ; return F(i – 2) + F(i – 1) } void main() { cout<<F(6)<< endl; } Cách 1 có hàm đệ quy F(i) để tính số Fibonacci thứ i. Quá trình tính toán có thể vẽ như cây dưới đây. Ta nhận thấy để tính F(6) nó phải tính một lần F(5), hai lần F(4), ba lầm F(3), năm lần F(2), ba lần F(1). } int F(100); // Bang phuong an void main { F[1] = F[2] = 1; for(int i =3; i<=6; i++) F[i] = F[i-2] + F[i -1] cout<<F(6)<< endl;

Hàm đệ quy tính số Fibonacci Cách 2: Trước hết nó tính sẵn F[1] và F[2], từ đó tính tiếp F[3], lại tính tiếp được F[4], F[5], F[6]. Đảm bảo mỗi giá trị Fibonacci chỉ phải tính một lần.
3

3. Một số bài toán quy hoạch động 3.  Vì quy hoạch động là đi giải tất cả bài toán con.  Không gian lưu trữ lời giải các bài toán con để tìm cách phối hợp chúng gọi là bảng phương án của quy hoạch động.  Giải tất cả các bài toán cơ sở.Trước khi áp dụng phương pháp quy hoạch động ta phải xem xét phương pháp đó có thỏa mãn những yêu cầu dưới đây hay không:  Bài toán lớn phải phân rã được thành nhiều bài toán con mà có sự phối hợp lời giải của các bài toán con đó cho ta lời giải bài toán lớn.3.  Dựa vào bảng phương án.  Dùng công thức truy hồi phối hợp những lời giải của những bài toán nhỏ đã lưu trong bảng phương án để tìm lời giải của những bài toán lớn hơn và lưu chúng vào bảng phương án. Các bước cài đặt một chương trình sử dụng quy hoạch động. Cần chọn những gói hàng nào để bỏ vào một ba lô sao tổng giá trị của các gói hàng đã chọn là lớn nhất nhưng tổng khối lượng của chúng không vượt quá khối lượng M cho trước.  Quá trình từ bài toán cơ sở tìm ra lời giải bài toán ban đầu phải qua hữu hạn bước.) để phối hợp chúng thì phương pháp quy hoạch động cũng không thể thực hiện được. Gói hàng thứ i có khối lượng là A[i] và giá trị C[i]. Cho tới khi bài toán ban đầu tìm được lời giải. nên nếu không đủ không gian vật lý lưu trữ lời giải (bộ nhớ. Bài toán ba lô 1 (knapsack) Cho n gói hàng. lưu các lời giải vào bảng phương án. M = 13 Tổng giá trị của các gói hàng bỏ vào ba lô: 16 4 . Các khái niệm  Bài toán giải theo phương pháp quy hoạch động gọi là bài toán quy hoạch động  Công thức phối hợp nhiều nghiệm của các bài toán con để có nghiệm của bài toán lớn gọi là công thức truy hồi (hay phương trình truy toán) của quy hoạch động  Tập tất cả các bài toán nhỏ nhất có ngay lời giải để từ đó giải quyết các bài toán lớn hơn gọi là cơ sở quy hoạch động.1. đĩa…. Ví dụ: n = 5. Mỗi gói chỉ chọn 1 hoặc không chọn. truy vết tìm ra nghiệm tối ưu 3.

v – A[i]) + C[i]) } Bài toán nhỏ nhất ứng với i = 0 ta có: F(0. 4). v) = F(i -1..M] chứa giá trị của các F(i. v – A[i]) + C[i]) } Ví dụ bảng phương án: 5 . 3(5. 5(1. v) = Max{ F(i -1. v) = Max{ F(i -1.Nếu gói hàng thứ i không được chọn thì: F(i. F(i -1. v) = F(i -1.. v) • Trường hợp A[i] <= v: F(i. v) . v).n][0. v).Điền số 0 cho các ô trên dòng 0 . v) là tổng giá trị lớn nhất của các gói hàng được chọn trong i gói hàng sao cho tổng khối lượng không lớn hơn v. 5). v) = F(i -1. v – A[i]) + C[i] → F(i.Các gói được chọn: 1(3.Sử dụng công thức đệ qui và giá trị trên dòng (i -1) để tính dòng i • Trường hợp A[i] > v: F(i. v) = F(i -1. F(i -1.  Trường hợp A[i] > v: F(i.  Nếu chọn thêm món hàng thứ n thì tổng khối lượng được chọn trong (n-1) món hàng không lớn hơn (M-A[n]) Suy ra bài toán có 2 tham số: số món hàng và khối lượng giới hạn Lập công thức đệ qui Gọi F(i. v)  Trường hợp A[i] <= v: . 2(4. v)  Cách tính giá trị trên bảng phương án: . v) = 0 Xây dựng bảng phương án:  Cấu trúc bảng phương án: Dùng mảng F[0. 1) Tham số thể hiện kích thước bài toán  Kết quả bài toán là tổng giá trị lớn nhất của các món hàng được chọn trong n món sao cho tổng khối lượng không lớn hơn M cho trước. ký hiệu là F(n)  Tham số thể hiện kích thước bài toán là số món hàng n  Giá trị của F(n) có thể được tính từ giá trị của F(n-1) cộng thêm hoặc không cộng thêm giá trị của món hàng thứ n nhưng tổng khối lượng không lớn hơn M. 6).Nếu gói hàng thứ i được chọn thì: F(i.

if (A[i] <= v && F[i. ta truy tiếp ô F[i-1. v-A[i]]. // Điền số 0 cho dòng 0 của bảng for (i = 1. v] = F[i–1. v] thì gói thứ i không được chọn. v] = F[i-1. v <= M. i <= n. 6 . v). v – A[i]) + C[i]) } Thuật toán tạo bảng phương án void TaoBangPhuongAn(F[0. v) • Trường hợp A[i] <= v: F(i. ta truy tiếp ô F[i-1.. v) = Max{ F(i -1. } } Truy vết tìm lại các gói hàng đã chọn Bắt đầu từ ô F[n. M] trên dòng n ta dò ngược về dòng 0 theo nguyên tắc:  Nếu F[ i. v] < F[i-1. v]. F(i -1. v++) F[0. v .. v) = F(i -1. v++) { F[i.• Trường hợp A[i] > v: F(i. v . v] = F[ i-1. v] = 0.A[i] ] + C[i]) F[i.n][0. v] thì gói thứ i được chọn.  Nếu F[ i. v]. v] <> F[i–1.A[i] ] + C[i].M]) { for (v=0. v <= M. i++) for (v=0.

.n][0. M = 13 Tổng giá trị của các món hàng bỏ vào ba lô: 19 Các món được chọn: 1 gói hàng loại 1 có khối lượng 3 và giá trị 4 5 gói hàng loại 4 có khối lượng 2 và giá trị 3 Xác định công thức đệ quy 7 .. Món hàng thuộc loại hàng i có khối lượng A[i] và giá trị C[i]. Cho biết số lượng món hàng từng loại hàng được chọn Ví dụ: n = 5. v]) { <Món hàng thứ i được chọn >. v = v – A[i]. } } 3.2. M] trên dòng n: i = n. i > 0. v = M. Số lượng các món hàng của mỗi loại không hạn chế.3. for (. i --) if (F[i.Thuật toán truy vết tìm lại các gói hàng đã chọn void TruyVet(F[0.Bài toán ba lô 2 Cho n loại hàng.M]) { Bắt đầu từ ô F[n. Cần chọn các món hàng trong từng loại để bỏ vào một ba lô sao cho tổng giá trị của các món hàng đã chọn là lớn nhất nhưng tổng khối lượng của chúng không vượt quá khối lượng M cho trước. v] != F[i-1.

v) = F(i-1. v) = F(i-1. v) = Max{F(i-1. v) = 0  Với i > 0 : ..Mảng S[1.1.1. v) = F(i-1. v) = F(i . v/A[i]] Xây dựng bảng phương án:  Cấu trúc bảng phương án: dùng 2 mảng .Nếu loại hàng i không được chọn thì: F(i. v] = k  Cách tính giá trị trên bảng phương án: . v) . v) 8 . v/A[i]] Bài toán nhỏ nhất ứng với i = 0 hay v=0 ta có: F(0. v)  Trường hợp A[i] <= v: . v): S[i. v) = Max{ F(i-1. v) = 0 Công thức đệ quy Gọi F(i. v) là tổng giá trị lớn nhất của các món hàng được chọn có tổng khối lượng <= v trong i loại hàng đầu tiên  Với i = 0 : F(i. v) = F(i . v) = F(i .n][1. v – A[i]*k) + C[i]*k } k ∈ [0.A[i] > v : F(i.  Trường hợp A[i] > v: F(i. v) .. v) .A[i] > v : F(i. v – A[i]*k) + C[i]*k Do đó: F(i. v] chứa giá trị của các F(i.Mảng F[0.Gọi F(i.1..v] chứa số món hàng loại i được chọn Nếu F(i. v] = 0 Ngược lại S[i..Điền số 0 cho các ô trên dòng 0 và cột 0 của bảng F .M]: F[i.Sử dụng công thức đệ quy và giá trị trên dòng i -1 để tính dòng i của bảng F và bảng S Ví dụ: Lập bảng phương án F  Với i > 0 : .n][0. v – A[i]*k) + C[i]*k } với k ∈ [0.Nếu có k món hàng loại i được chọn: (1 <= k <= v/A[i] ) F(i.A[i] <= v : F(i. v) là tổng giá trị lớn nhất của các món hàng được chọn sao cho tổng khối lượng <= v trong i loại hàng.M]: S[i.

k <= v/A[i]... v] = k.A[i]*k ] + C[i]*k.n][0. S[1. v . v ..v) Bảng S[i. S[i.A[i]*k ] + C[i]*k) { F[i. v) = Max{ F(i-1. v/A[i] ] Bảng F(i. S[i..M]) { <Điền số 0 cho dòng 0 và cột 0 của bảng F[0.n][1. v++) { F[i. for (i = 1.. if (v >= A[i]) for(k = 1. 9 .. v] Thuật toán tạo bảng phương án void TaoBangPhuongAn(F[0. v]. v – A[i]*k) + C[i]*k } với k ∈ [0.M]>. v] < F[i-1.A[i] <= v : F(i. v <= M. v] = F[i-1. k++) if (F[i.. v] = 0. i++) for (v=1.M]. i <= n. v] = F[i-1.n][0.

Bài toán dãy con có tổng chia hết cho k 10 . Thuật toán truy vết tìm lại các gói hàng đã chọn void TruyVet(S[1.n][1.  Nếu S[i.Truy tiếp ô S[i-1. v] >. v]*A[i] ].M]) { i = n.Loại hàng i được chọn với số lượng là S[i.} } } Truy vết tìm lại các gói hàng đã chọn Bắt đầu từ ô S[n. v] . v] != 0) { <in số lượng gói hàng i trong S[i. . v = v – S[i. } } 3. v]*A[i]. v = M while (i > 0) { if (S[i.. v] = 0 thì : . v .S[i. M] trên dòng n ta dò ngược về dòng 1 theo nguyên tắc:  Nếu S[i. v] <> 0 thì : .. } i = i – 1.Loại hàng i không được chọn. v].Truy tiếp ô S[i-1.3.3.

. Nếu dãy con dài nhất không có A[i] thì F(i) = F(i-1) Với F(i-1) = chiều dài dãy con dài nhất trong miền [1.Cho một dãy A gồm n số nguyên và một số nguyên dương k..Nếu r > 0 : do (r + k .i-1] có tổng chia hết cho k 2.i] có tổng chia với k dư là v.r + k) mod k 3. Hãy tìm một dãy con (không nhất thiết phải liên tiếp nhau) dài nhất có tổng các số chia hết cho số k. (a + b) mod k = (r + z) mod k 2.1] có tổng chia hết cho k . 1. Ví dụ: n = 6 và k = 5 Chiều dài dãy con: 4 Các phần tử được chọn là : 1 Có giá trị tương ứng là : : 11 Nhắc lại phép toán mod Giả sử r = a mod k và z = b mod k Ta có: 1.i] có tổng chia hết cho k.r) mod k = 0 nên F(i-1) bằng chiều dài dãy con dài nhất trong miền [1.Nếu r = 0: thì F(i-1) = chiều dài dãy con dài nhất trong miền [1.. 11 . (-r) mod k = (.. (r + z) mod k = v → z = (v – r) mod k = (v – r + k) mod k 2 6 5 20 6 8 Xác định tham số Gọi F(i) = chiều dài dãy con dài nhất trong miền [1.(i-1)] có tổng chia với k dư (k-r) Tham số thể hiện kích thước của bài toán: kích thước miền và số dư của tổng chia với k Lập công thức đệ qui Gọi F(i. v) = chiều dài dãy con dài nhất trong miền [1. Nếu dãy con dài nhất có chứa A[i]: thì F(i) = F( i-1) + 1 Gọi r = A[i] mod k .i..

v – r + k)>0 thì F(i.F(1. v-r+k)>0: F(i. v) = F(i-1. v) = F(i-1.1. v-r+k) + 1 thay (v .Nếu v = r thì : F(i. v .Nếu v < r và F(i-1. v. v) = Max{F(i-1. (v.r +k) mod k) > 0 thì F(i. v) = 1 nếu r = v  Với i > 1 : .Nếu v – r < 0 và F(i-1. v) = Max {F(i-1. v – r) +1 } .r) >0 thì F(i. v) = 0 nếu r <> v . F(i-1. v – r + k) + 1} Tinh chế công thức đệ quy Gọi r = A[i] mod k • Với i = 1: . v). v).r) mod k = (v – r + k) mod k Bài toán nhỏ nhất ứng với i = 1: • F(1. v) = 0 nếu r <> v . v) 2. F(i-1.v)= 1 nếu r = v Công thức đệ quy Gọi r = A[i] mod k  Với i = 1: . Nếu dãy con dài nhất không có A[i] thì F(i. v) = F(i-1. (v – r + k) mod k) +1 } Xây dựng bảng phương án:  Cấu trúc bảng phương án: 12 . v) = F( i-1.Nếu v – r = 0 : F(i. v). v) = Max {F(i-1. F(i-1. F(i-1.Nếu v<>r và F(i-1. 0) +1 } . F(i-1.Nếu v > r và F(i-1. v) = F( i-1.r)>0: F(i.F(1.Nếu v = r thì : F(i.r) + 1 . v) = Max {F(i-1.Nếu v – r > 0 và F(i-1. v) = Max {F(i-1. v . v . v) = 1 nếu r = v • Với i > 1 : .F(1. v).r) + 1 . 0) +1 } . v).v)= 0 nếu r <> v • F(1.F(1. 0) + 1 . Nếu dãy con dài nhất có chứa A[i]: Gọi r = A[i] mod k ta có F(i.

0 ]) F[i.n][0.n][0. v). v] = 0 . F[i. i <= n.r + k)%k] + 1. v] = (A[i]%k == v) ? 1 : 0.Sử dụng công thức đệ quy và giá trị trên dòng i -1 để tính dòng i Ví dụ bảng phương án: • Với i > 1 : . i++) for (v=0. v <= k-1.Nếu v = r thì : F(i. v <= k-1. (v . v)  Cách tính giá trị trên bảng phương án: . v] = 1 ngược lại F[1. else if (F[i-1.Điền giá trị dòng 1: Nếu A[1] mod k = v thì F[1. v] = F[ i -1. (v-r+k) mod k) > 0 thì F(i.. 0] + 1.Nếu v<>r và F(i-1. v++) { r = A[i] % k. v). v]. v] = F[i-1..k-1]) { for (v=0.. } } 13 . v] <= F[i-1. v) = Max {F(i-1. (v – r + k) mod k) +1 } i 1 2 3 4 5 6 r = A[i] | v 1 1 2 2 0 3 0 0 4 | 0 3 | 0 3 | 3 0 | 4 2 | 4 1 1 0 | 1 4 | 1 4 | 3 1 | 4 3 | 4 2 0 1 | 2 0 | 2 0 | 2 2 | 3 4 | 5 3 0 0 | 2 1 | 2 1 | 2 3 | 3 1 | 5 4 0 3 | 0 2 | 3 2 | 3 4 | 4 2 | 6 Thuật toán tạo bảng phương án void TaoBangPhuongAn(F[1.r + k)%k]) F[i. if (v == r && F[i. v] = F[i-1. (v . F(i-1. v) = Max {F(i-1. F(i-1. (v ..r + k)%k] >0 && F[i. v] <= F[i-1.K-1] chứa giá trị của các F(i. for (i = 2.Dùng mảng F[1. 0) +1 } . v++) F[1.

 Xét 2 cách ghi nhận kết quả các bài toán con: 14 .A[i] được chọn .L(n) = L(n-1) +1 nếu dãy con dài nhất trong miền [1.. Hãy loại bỏ khỏi dãy một số phần tử để được một dãy con không giảm dài nhất... i 1 2 3 4 5 6 r = A[i] | v 1 1 2 2 0 3 0 0 4 | 0 3 | 0 3 | 3 0 | 4 2 | 4 1 1 0 | 1 4 | 1 4 | 3 1 | 4 3 | 4 2 0 1 | 2 0 | 2 0 | 2 2 | 3 4 | 5 3 0 0 | 2 1 | 2 1 | 2 3 | 3 1 | 5 4 0 3 | 0 2 | 3 2 | 3 4 | 4 2 | 6 3.n] . 0] trên dòng n ta dò ngược về dòng 0 theo nguyên tắc: • Nếu F[i–1. Hãy chỉ ra dãy con không giảm dài nhất ? Xác định tham số thể hiện kích thước bài toán  Gọi L(n) là độ dài dãy con không giảm dài nhất trong miền [1. v] > F[i–1.3.4.n-1] có A[n]  Do đó tham số thể hiện kích thước bài toán là số phần tử n. v].n-1] không có A[n] . (v-r+k)%k]: .Tìm dãy con không giảm dài nhất Cho một dãy gồm n số nguyên.L(n) = L(n-1) nếu dãy con dài nhất trong miền [1.Truy tiếp ô F[i -1. ta truy tiếp ô F[i -1. • Ngược lại thì A[i] không được chọn. (v-r+k)%k]. (v-r+k)%k] > 0 và F[i.Truy vết Bắt đầu từ ô F[n. Ví dụ: với n = 10 và dãy A được cho trong bảng. In ra dãy con đó.

Với các phần tử i từ 2 đến n: • Nếu A[i] < A[j] với mọi j < i thì: L(i) = 1 và Truoc(i) = 0 • Ngược lại thì . Truoc[1] = 0..Lập công thức đệ qui Gọi L(i) là độ dài dãy con dài nhất trong dãy A[1.n]: L[i] chứa giá trị của L(i) ..Mảng L[1. Nếu A[i] < A[j] với mọi j < i thì: L(i) = 1 Ngược lại thì : L(i) = Max{ L(j) : j < i và A[j] <= A[i] } + 1 Bài toán nhỏ nhất với đoạn A[1.i] và có A[i] là phần tử cuối dãy con dài nhất đó.1] thì L(1) = 1 Xây dựng bảng phương án: .n]: Truoc[i] ghi chỉ số phần tử kề trước i trong dãy con dài nhất mà i là phần tử cuối dãy.Mảng Truoc[1.. i <= n. for (i = 2.Truoc[i] = k sao cho L(k)= Max{ L(j) : j < i và A[j] <= A[i] } Thuật toán tạo bảng phương án void TaoBangPhuongAn() { L[1] = 1. Cách tính giá trị trên bảng phương án: .Gán L[1] = 1 và Truoc[1] = 0 .. i++) 15 .L(i) = Max{ L(j) : j < i và A[j] <= A[i] } + 1 .

for (j = i-1. Truoc[i] = j. j--) if (A[j] <= A[i] && L[j] >= L[i]) { } L[i] = L[j] + 1. Truoc[i] = 0. Truy tiếp sang phần tử có chỉ số Trươc[i] cho đến khi phần tử Truoc[i] = 0. 16 . j--) if (B[j] > B[i]) i = j.{ L[i] = 1. for ( j = n-1. j >= 1. while ( i > 0) { <in thông tin A[i] thuộc dãy con tối ưu>. j >=1. Thuật toán tìm lại các phần tử trên dãy con tối ưu void TruyVet() { i = n. } } Truy vết tìm lại các phần tử trên dãy con Bắt đầu từ phần tử i có giá trị L[i] có lớn nhất là phần tử cuối cùng trong dãy con dài nhất. i = Truoc[i].

tiền đền bù khi sa thải một công nhân là ST.Smax  C(i.  Chi phí trả nhân công của tháng thứ T bao gồm : .. j) là chi phí tối thiểu của i tháng đầu tiên nếu tại tháng thứ i có j công nhân được thuê.Tiền dịch vụ nếu số nhân công của tháng T lớn hơn số nhân công tháng T-1 hay tiền sa thải nếu số nhân công trong tháng T nhỏ hơn số nhân công của tháng T-1. Cần phải thuê hay sa thải bao nhiêu công nhân mỗi tháng để tổng chi phí nhân công của dự án là nhỏ nhất. j) = j * (DV + LT) với j = Scn[1].5. Lập lịch thuê nhân công Có một dự án kéo dài trong T tháng.} <in thông tin A[i] thuộc dãy con tối ưu>. số công nhân tối thiểu cần trong tháng thứ i là Scn[i]. Biết rằng. 17 .  Kích thước bài toán phụ thuộc vào 2 tham số: số tháng và số nhân công của tháng Lập công thức đệ qui  Scn[i] lưu số công nhân cần thuê cho tháng thứ i  Smax là số công nhân của tháng cần nhiều người nhất  Bài toán con nhỏ nhất ứng với i = 1 (tháng đầu tiên): C(1. } 3. tiền dịch vụ khi thuê một công nhân mới là DV.Tiền lương trả cho số nhân công của tháng T và . Xác định tham số thể hiện kích thước bài toán  Tham số thể hiện kích thước bài toán là số tháng T  Tổng chi phí nhân công trong T tháng được tính từ tổng chi phí nhân công của T-1 tháng cộng thêm chi phí trả nhân công của tháng thứ T. lương tháng mỗi công nhân phải trả là LT.3. người quản lý cần phải lập lịch sử dụng công nhân mỗi tháng cho dự án.

j) + chi phí sa thải j người} j=Scn[T]. i++) for (j=Scn[i].. j] ghi nhận giá trị C(i.Smax..Smax]: C[i.. i <= T. j) = j * (DV + LT) với j = Scn[1].. k = Scn[i-1].. j] = j * (DV + LT).Smax)  Kết quả bài toán là: Kq = Min{C(T. j) = Min{ C(i-1... j =Scn[i].Smax. j) = Min{ C(i-1.. 1. k) + chi phí để từ k người thành j người } ( i=1. j) + (j * ST) j=Scn[T]. j <= Smax. j) C(1. j] := k là số người thuê ở tháng thứ i-1 để có C[i. j++) C[1. k) + chi phí để từ k người thành j người } ( i=2. k = Scn[i-1]..Smax Xây dựng bảng truy vết số công nhân Mảng Truoc[1.. j) = C(T. j <= Smax. j)  Mảng C[1.Smax) C(T+1..T.T..T+1. j] Thuật toán tạo bảng phương án C và Truoc { for (j=Scn[1].. j++) 18 .Smax]: Truoc[i.C(i.Smax C(i. 1. j =Scn[i]. for (i = 2.T.Smax Xây dựng bảng chứa C(i.

4. k <= Smax. cần chia N gói kẹo thành hai phần sao cho độ chênh lệch số kẹo giữa hai gói là ít nhất. Với mỗi loại hoa i ta biết giá trị thẩm mỹ khi cắm hoa đó k = Truoc[i. j <= Smax. j] = k. if (k > j) X = X + (k – j)*DV. Hãy cho biết mỗi loại tiền cần bao nhiêu tờ sao cho tổng số tờ là ít nhất. n). j]) { C[i. Tờ giấy bạc thứ i có mệnh giá A[i]. j ]. for (k=Scn[i-1]. Số tờ mỗi loại không giới hạn. k] . j] = X. i--) { } } Bài tập 1. else X = X + (j – k)*ST if (X< C[i. Cho n loại tờ giấy bạc. j ]) { k = j. 3. for (j=Scn[T]+1. Cần cắm k loại hoa khác nhau vào n lọ xếp thẳng hàng sao cho loại hoa có số hiệu nhỏ được đặt trước hoa có số hiệu lớn. 2. j] = MAXINT. k++) { X = C[i-1. j++) C[T+1. Giả thiết loại tiền mệnh giá A[i] có B[i] tờ (i := 1. k]. j] = C(T. thì thông báo “KHONG DOI DUOC”. Cần chi trả cho khách hàng số tiền M đồng. Có N gói kẹo. k = Scn[T]. Cần chi trả cho khách hàng số tiền M đồng. } } } for (j=Scn[T]. j++) if (S > C[T+1. Cho n loại tờ giấy bạc. } Thuật toán truy vết số công nhân mỗi tháng { //Tìm số nhân công của tháng thứ T S = C[T+1. S =C[T+1. <Tháng i-1 cần k công nhân> 19 . thì thông báo “KHONG DOI DUOC”. Không được bóc bất kỳ một gói kẹo nào. Scn[T] ]. j) + (j * ST) . Truoc[i.{ C[i. gói thứ i có Ai cái kẹo. i > 1. } <Tháng T cần k công nhân> for (i=T. Nếu không đổi được. Tờ giấy bạc thứ i có mệnh giá A[i]. j <= Smax. Nếu không đổi được. Hãy cho biết mỗi loại tiền cần bao nhiêu tờ sao cho tổng số tờ là ít nhất.

Hãy trình bày giải thuật chọn lựa ra các ngọn đồi đặt các trạm bơm sao cho số ngọn đồi được chọn là nhiều nhất. Hãy trình bày thuật giải để chọn lựa các hợp đồng theo yêu cầu trên. giá trị hợp 20 . phải xây dựng kéo hệ thống dẫn nước từ dưới thung lũng lên bản băng qua các ngọn đồi. 7. Hợp đồng thứ i có giá trị là Ci (số nguyên) và cần Ai nhân sự để thực hiện. Do số lượng nhân sự của công ty có hạn.vào lọ j là v[i. 5. a. mỗi ngọn đồi được gán một số thứ tự tăng theo hướng từ thung lũng lên vùng cao. Hãy trình bày thuật toán để chọn trong N file dữ liệu các file đính kèm vào một thư điện tử theo yêu cầu trên. Việc xây dựng công trình cấp nước sạch ở các bản vùng cao rất khó khăn. giá trị hợp đồng và số lượng nhân sự của các hợp đồng đã chọn. người ta đặt các trạm bơm nối tiếp trên từng ngọn đồi dẫn từ thung lũng lên bản vùng cao.j]. N ≤ 50 và file thứ i trong N file dữ liệu có kích thước là Ai KByte (là số nguyên dương). Một hộp thư điện tử cho phép gửi đính kèm một hoặc nhiều file vào một thư điện tử sao cho tổng dung lượng các file đính kèm trên thư điện tử không vượt quá kích thước M KByte cho trước. Giả sử. Do số lượng nhân sự của công ty có hạn. người ta cần chọn trong N file dữ liệu các file để đính kèm vào một email sao cho tổng dung lượng của các file đính kèm là lớn nhất nhưng không vượt quá kích thước M. Một công ty máy tính nhận được N hợp đồng (N ≤ 50) lắp đặt hệ thống máy tính tại N công ty. nên Công ty muốn ưu tiên chọn một số hợp đồng để thực hiện trước sao cho tổng giá trị của các hợp đồng đã chọn là lớn nhất nhưng tổng số nhân sự thực hiện các hợp đồng đó không vượt quá số lượng M nhân sự (M ≤ 100) hiện có của công ty. nên Công ty muốn ưu tiên chọn một số hợp đồng để thực hiện trước sao cho tổng giá trị của các hợp đồng đã chọn là lớn nhất nhưng tổng số nhân sự thực hiện các hợp đồng đó không vượt quá số lượng M nhân sự (M ≤ 100) hiện có của công ty. M ≤ 100. hai trạm bơm kề nhau không nhất thiết đặt trên hai ngọn đồi kề nhau. Hợp đồng thứ i có giá trị là Ci (số nguyên) và cần Ai nhân sự để thực hiện. liệt kê kích thước các file đã chọn. Một công ty máy tính nhận được N hợp đồng (N ≤ 50) lắp đặt hệ thống máy tính tại N công ty. cho biết tổng giá trị của các hợp đồng đã chọn. 6. b. Để có số thư điện tử gửi đi là ít nhất. theo nguyên tắc ngọn đồi sau phải cao hơn ngọn đồi trước. Để thuận lợi cho việc dẫn nước. Hãy trình bày thuật giải để chọn lựa các hợp đồng theo yêu cầu trên. Giả sử có N ngọn đồi (N ≤ 100). ngọn đồi thứ i có độ cao Ai (là một số nguyên dương). 8. Sử dụng ngôn ngữ C++ cài đặt giải thuật trên. Hãy tìm phương án cấm các loại hoa trên vào n lọ sao cho tổng giá trị thẩm mỹ là lớn nhất. cho biết tổng giá trị của các hợp đồng đã chọn.

21 .

Hiểu và nắm vững bản chất.Nghiên cứu một lớp cây đặc biệt: cây nhị phân. hàng dưới là các đỉnh con của gốc. Trước hết chúng ta đưa ra định nghĩa cây thông qua các khái niệm trong đồ thị định hướng. nếu A là cha của B.1: gốc ở trên cùng. Trừ ông tổ của dòng họ này.Chương 4 CÂY MỤC TIÊU CỦA CHƯƠNG . Một ví dụ điển hình về cây là tập hợp các thành viên trong một dòng họ với quan hệ cha con. Biểu diễn hình học một cây 22 . Xem xét các đặc điểm của đồ thị định hướng này. mỗi một người trong dòng họ là con của một người cha nào đó trong dòng họ. chúng ta đưa ra định nghĩa cây như sau: Cây là một đồ thị định hướng thỏa mãn các tính chất sau: • Có một đỉnh đặc biệt được gọi là gốc cây • Mỗi đỉnh C bất kỳ không phải là gốc. có đoạn nối từ đỉnh cha tới đỉnh con (cần lưu ý cung luôn luôn đi từ trên xuống dưới) Hình 4. NỘI DUNG BÀI GIẢNG LÝ THUYẾT 4. tồn tại duy nhất một đỉnh P có cung đi từ P đến C.1.Các khái niệm cơ bản Chúng ta có thể xác định khái niệm cây bằng hai cách: đệ quy và không đệ quy. dưới một hàng là các đỉnh con của các đỉnh trong hàng đó. . thì trong đồ thị có cung đi từ đỉnh A tới đỉnh B. Biểu diễn dòng họ dưới dạng đồ thị hướng: quan hệ cha con được biểu diễn bởi các cung của đồ thị. Đỉnh P được gọi là cha của đỉnh C. các khái niệm cơ bản về cây và các CTDL biểu diễn cây .1.Sinh viên cần nắm vững phần lý thuyết để có thể hình thành các kỹ năng trong việc tiếp cận và giải các bài toán cụ thể. Người ta quy ước biểu diễn cây như trong hình 4. và C là con của P • Có đường đi duy nhất từ gốc tới mỗi đỉnh của cây.

Sau này chúng ta chỉ quan tâm đến các cây được sắp. Dễ dàng thấy rằng. F.. là quan hệ tổ tiên con cháu. Các đỉnh không có con được gọi là lá. trong cây ở hình 4. đỉnh con cả là đỉnh ngoài cùng bên trái.1. Trong biểu diễn hình học. Một đỉnh không phải là lá được gọi là đỉnh trong. Nếu đỉnh A là con của gốc. b2.k-1) được gọi là em liền kề của đỉnh bi. Tập chỉ có một đỉnh a là cây. các đỉnh trong cùng một mức là đỉnh con của một đỉnh nào đó ở mức trên.Sau đây chúng ta sẽ đưa ra một số thuật ngữ hay được dùng đến sau này. Các đỉnh cùng cha được xem là anh em. C. cây trong hình 4. . Chẳng hạn. G. Cây là một tập hợp không rỗng T các phần tử (được gọi là các đỉnh) được xác định đệ quy như sau: • gốc là a. Chẳng hạn.1 có độ cao là 3. Cây này được gọi là cây con của cây đã cho.. các đỉnh lá là E. đỉnh G có độ sâu là 2. hay B là con cháu của A.1 được phân thành 3 mức: mức 1 chỉ gồm có gốc. trong hình 4. Cây là một cấu trúc dữ liệu phân cấp: Các đỉnh của cây được phân thành các mức.. . mức 2 gồm các đỉnh A. D là anh em. Độ cao của cây là số đỉnh nằm trên đường đi dài nhất từ gốc tới một lá.1 các đỉnh B. 2. Độ cao của cây chính là mức lớn nhất của cây. gốc cây là tổ tiên của các đỉnh còn lại trong cây. Mức của mỗi đỉnh được xác định đệ quy như sau: Gốc ở mức 1 Mức của một đỉnh = mức của đỉnh cha + 1 Như vậy. B. cây trong hình 4.. G. F. Trong cây nếu có đường đi từ đỉnh A tới đỉnh B thì A được gọi là tổ tiên của B. đỉnh b k là đỉnh ngoài cùng bên phải.. Một đỉnh bất kỳ A cùng với tất cả các con cháu của nó lập thành một cây gốc là A. bk (k ≥1). Trong hình 4. Chẳng hạn. D. khi đó đỉnh b1 được gọi là con cả của a. Khái niệm cây còn có thể định nghĩa một cách khác: định nghĩa đệ quy. cây này có 23 . còn đỉnh bi+1 (i=1. Giả sử a là một đỉnh và các con của nó được sắp xếp theo thứ tự b1. Ví dụ. thì cây con gốc A được gọi là cây con của gốc. Cây được sắp là cây mà các đỉnh con của mối đỉnh được sắp sếp theo một thứ thứ tự xác định. Chẳng hạn. C.1. Định nghĩa đệ quy. độ cao của cây là độ cao lớn nhất của cây con của gốc cộng thêm 1. Trên đây chúng ta đã định nghĩa cây như một đồ thị định hướng có một số tính chất đặc biệt. C. Mở rộng của quan hệ cha con. mức 3 gồm các đỉnh E. Độ sâu của một đỉnh là độ dài đường đi từ gốc tới đỉnh đó.

. mỗi đỉnh chỉ có nhiều nhất K đỉnh con. B C D 24 E F G . ta cần có một con trỏ ngoài trỏ tới gốc cây. Sau đây. Giả sử r là một đỉnh mới không có trong các cây đó. k) lập thành một cây có gốc là đỉnh r. trong đó hai cây bất kỳ không có đỉnh chung. Các cây Ti (i=1.. con trỏ root: root Node <Item>* root.1 được cài đặt bởi CTDT được biểu diễn hình học trong hình 4. Vì vậy..2. template <class Item> { Item data.. rk . Phương pháp 1 (chỉ ra danh sách các đỉnh con của mỗi đỉnh). cây trong hình 4. ít được sử dụng. }. A với cách cài đặt này... mỗi đỉnh của cây được biểu diễn bởi một cấu trúc gồm hai thành phần: một biến data lưu dữ liệu chứa trong đỉnh đó và một mảng child các con trỏ trỏ tới các đỉnh con.Giả sử T1. Giả sử.. Song cách này không thuận tiện. Và như vậy. chúng ta trình bày hai phương pháp cài đặt cây thông dụng nhất. Node* child [K]. khi đó ta có thể mô tả mỗi đỉnh bởi cấu trúc sau: const int K = 10... Cài đặt cây Cây có thể cài đặt bởi các CTDL khác nhau. .. k) được gọi là các cây con của gốc r. chúng ta có thể dễ dàng đưa ra các thuật toán đệ quy cho các nhiệm vụ xử lý trên cây.. r2.. Chúng ta có thể sử dụng mảng để cài đặt cây.. Với mỗi đỉnh của cây. ta sử dụng một con trỏ trỏ tới một đỉnh con của nó.. Khi đó tập T gồm đỉnh r và tất cả các đỉnh trong các cây Ti (i=1. Cây T được biểu diễn hình học như sau: • Sử dụng định nghĩa cây đệ quy. . . và r là đỉnh cha của đỉnh ri hay ri là đỉnh con của r (i=1.. . .. Tk (k ≥ 1) là các cây có gốc tương ứng là r1. T2. k).... Chúng ta có thể truy cập tới một đỉnh bất kỳ trong cây bằng cách đi theo các con trỏ bắt đầu từ gốc cây.

2. nếu sử dụng mảng con trỏ. Trong trường hợp đó. ta chỉ sử dụng hai con trỏ: con trỏ firstChild trỏ tới đỉnh con cả và con trỏ nextSibling trỏ tới em liền kề. Trong một cây. Thay vì sử dụng mảng con trỏ. root A Node data. sẽ lãng phí bộ nhớ. nextSibling. ta có thể truy cập tới đỉnh bất kỳ trong cây. Chúng ta cũng cần có một con trỏ ngoài root trỏ tới gốc cây như trong phương pháp 1. số đỉnh con của các đỉnh có thể rất khác nhau. Mỗi đỉnh của cây được biểu diễn bởi cấu trúc sau: template <class Item> struct { Item Node* }. Dễ dàng thấy rằng. firstChild.Hình 4. cây trong hình 4.1 được cài đặt bởi CTDL như trong hình 4.3. Với cách này. Node*. Ta có nhận xét rằng. Cài đặt cây bởi mảng con trỏ. B C D E F G 25 . xuất phát từ gốc đi theo con trỏ firstChild hoặc con trỏ nextSibling. Phương pháp 2 (chỉ ra con cả và em liền kề của mỗi đỉnh). các con trỏ nextSibling liên kết các đỉnh tạo thành một danh sách liên kết biểu diễn danh sách các đỉnh con của mỗi đỉnh.

Có ba phương pháp duyệt cây hay được sử dụng nhất trong các ứng dụng là: duyệt cây theo thứ tự trước (preorder). Thứ tự các đỉnh được thăm theo phương pháp này là A.4. chỉ trừ khi nào không xuống dưới được nữa mới quay lên đỉnh cha để rồi lại tiếp tục đi xuống. luôn luôn đi sâu xuống thăm các đỉnh con. Cần chú ý rằng. Chẳng hạn. ta quay lên cha của nó và đi xuống thăm một đỉnh con tiếp theo (nếu có) của đỉnh cha đó. chẳng hạn như in ra các dữ liệu đó. G. Giả sử T là cây có gốc r và các cây con của gốc là T1. D. thì hành động hay được sử dụng là duyệt cây. • Duyệt lần lượt các cây con T1. Tk theo thứ tự trước. Khi dữ liệu được tổ chức dưới dạng cây.. C.3. để thuận tiện cho các xử lý. Duyệt cây T theo thứ tự trước có nghĩa là: • Thăm gốc r. Khi không đi sâu xuống được. Phân tích kỹ thuật duyệt cây theo thứ tự trước. 4. 26 . Các phương pháp duyệt cây được mô tả rất đơn giản bằng đệ quy. duyệt cây theo thứ tự trước có nghĩa là xuất phát thăm từ gốc. theo thứ tự trong (inorder) và theo thứ tự sau (postorder).. Tk (k>=0)... Do đó... rồi lại tiếp tục đi xuống. Quá trình đi thăm các đỉnh của cây trong hình 4.2.Hình 4. F. Như vậy. xét cây trong hình 4. Chúng ta xác định các phương pháp duyệt cây này. trong một số trường hợp. E. Duyệt cây Người ta thường sử dụng cây để tổ chức dữ liệu. Duyệt cây có nghĩa là lần lượt thăm các đỉnh của cây theo một trật tự nào đó và tiến hành các xử lý cần thiết với các dữ liệu trong mỗi đỉnh của cây..1. B.. T2. kỹ thuật duyệt cây theo thứ tự trước còn được gọi là kỹ thuật tìm kiếm theo độ sâu. rồi lại tiếp tục đi xuống thăm con cả của r 1.. sau đó đi xuống thăm con cả r 1 của gốc (r1 là gốc của cây con T1).1 được biểu diễn bởi hình 4. ta rút ra quy luật đi thăm các đỉnh của cây như sau: đầu tiên thăm gốc r . ta có thể đưa thêm vào cấu trúc Node một con trỏ parent trỏ tới đỉnh cha.. Cài đặt cây sử dụng hai con trỏ. tức là đạt tới một đỉnh không có con (lá). ..

Giả sử cây được cài đặt bằng phương pháp sử dụng hai con trỏ: firstChild và nextSibling. C. A. G. Khi đó hàm đệ quy Preorder được cài đặt như sau: template <class Item> void { if (root ! = NULL) { f (root  data). thứ tự các đỉnh của cây trong hình 4. Hàm f là hàm bất kỳ thực hiện các xử lý nào đó với dữ liệu có kiểu Item..Tk theo thứ tự sau • Thăm gốc r Chẳng hạn. Hàm này chứa một tham biến là con trỏ root trỏ tới gốc cây. C.Hình 4.. . G. void f(Item&)) P = root  firstChild. f).. D. A. Duyệt cây T theo thứ tự sau được tiến hành như sau: • Duyệt lần lượt các cây con T1.1 được thăm theo thứ tự là E. trong đó Item là kiểu của dữ liệu chứa trong đỉnh của cây. F. B. B.. Chúng ta đưa vào hàm Preorder một tham biến khác.4. Ví dụ. F. Các kỹ thuật duyệt cây được xác định đệ quy. C++ cho phép tham biến của một hàm có thể là hàm. Thăm các đỉnh của cây theo thứ tự trước Duyệt cây T theo thứ tự trong được quy định như sau: • Duyệt cây con T1 theo thứ tự trong • Thăm gốc r • Duyệt lần lượt các cây con T2. while (P ! = NULL) . vì vậy dễ dàng cài đặt các kỹ thuật duyệt cây bởi các hàm đệ quy.. } } 27 Preorder (Node<Item>* root.1. đó là hàm với khai báo sau: void f(Item&). Tk theo thứ tự trong. cũng với cây trong hình 4. Lưu ý rằng. các đỉnh được thăm theo phương pháp này lần lượt là E. node <Item>* { Preorder (P. P = P  nextSibling. . D. Sau đây ta viết hàm đệ quy duyệt cây theo thứ tự trước: hàm Preorder. Bây giờ chúng ta cài đặt các hàm duyệt cây.

Chúng ta cũng có thể cài đặt hàm Preorder không đệ quy. S. } } } Một cách tương tự. Muốn vậy chúng ta cần sử dụng một ngăn xếp để lưu các đỉnh nằm trên đường đi từ gốc tới đỉnh đang được thăm để khi tới một đỉnh mà không đi sâu xuống được thì biết được đỉnh cha của nó mà quay lên. // Khởi tạo ngăn xếp rỗng S lưu // các con trỏ. Hàm Preorder không đệ quy: template <class Item>. // Đẩy con trỏ P vào ngăn xếp S P = P  firstChild. } while (! S. while (P ! = NULL) { f (P  data). Empty ()) { P = S. Pop (). void f (Item)) { Stack <Node<Item>*> S. ngăn xếp sẽ lưu các con trỏ trỏ tới các đỉnh.3. có thể viết ra các hàm đệ quy và không đệ quy thực hiện duyệt cây theo thứ tự trong: hàm Inorder. 4. P = P  firstChild. và duyệt cây theo thứ tự sau: hàm Postorder.3. Push (P). P = P  nextSibling. void Preorder (Node <Item>* root.1. Biểu diễn và duyệt cây tổng quát 4. // Loại con trỏ P ở đỉnh ngăn xếp. S. Biểu diễn cây tổng quát 28 . Thay vì lưu các đỉnh. Node <Item>* P = root while (P ! = NULL) { f (P  data). Push (P).

. cách dùng mảng chỉ số cha như đã dùng với cây nhị phân khá thích hợp với cây m-phân. A(i) = j nếu j là cha của nút i. Data là trường lưu trữ thông tin của nút. Dùng mô hình cây nhị phân với con trái nhất và nút em kế cận bên phải. trường Left_Child trỏ tới con trái nhất. Dùng mảng biểu diễn cây tổng quát. 1. còn trường Right_Sibling trỏ tới nút em kế cận bên phải của nút hiện tại 29 . Cũng có thể dùng danh sách liên kết biểu diễn cây tổng quát. 2. cũng có thể m không được xác định trước. bắt đầu từ con bên trái nhất đến con bên phải nhất. Tuy nhiên. .. Giả sử có n nút được đánh số là 1. Cây tổng quát Có thể hiểu là cây tổng quát là cây m-phân nào đó.. Mỗi nút có thể hình dung gồm ba trường chính: trong đó. 2. Dùng mảng A để biểu diễn cây T theo nguyên tắc: A(i) = 0 nếu nút i là gốc. Với cây m-phân mà dùng mảng để lưu trữ theo cách thông thường thì rõ ràng là có rất nhiều ô trống. Mỗi nút có một danh sách các con của nó. ngoài ra.Hình 4. Có thể m được xác định trước. 1. n.5.

3. Tuy nhiên cũng có thể xây dựng riêng thủ tục duyệt cây tổng quát nhằm tăng hiệu quả của phép duyệt. có nhiều cách duyệt tương ứng. 9. 10. 3.3. có thể sử dụng các cách duyệt cây nhị phân trong mục trước cho cây tổng quát chuyển đổi. 8. 6. 3. Với cây tổng quát 4.5. 8. Hình ảnh danh sách lên kết lưu trữ cây 4. 1. 5. 30 .Hình 4. Chẳng hạn. Duyệt cây tổng quát Với mỗi cách biểu diễn cây tổng quát. 8. 7. 7. 4. với cách biểu diễn thông qua cây nhị phân với con trái nhất và nút em kế cận bên phải. ta sẽ nhận được danh sách các đỉnh theo thứ tự: 1. 6. 3. 2.5 có được theo phương pháp duyệt trung thứ tự: 4.2. 5. 1. 5. 2. 6. 1. Danh sách các đỉnh của cây 4. nếu áp dụng phương pháp duyệt tiền thứ tự.5 4.5 có được theo phương pháp duyệt hậu thứ tự: 7. 10. 10 2.6. 2. 9. Danh sách các đỉnh của cây 4. 4. 9.

Cho cây: A B a c D E F G H I J K Hãy viết ra danh sách các đỉnh khi duyệt cây theo các thứ tự preorder. 2. Giả sử cây được biểu diễn bằng cách sử dụng hai con trỏ firstChild và nextSibling. 31 . Mô tả CTDL biểu diễn cây theo cách đó bằng các khai báo trong C + +. 3.Bài tập 1. hãy viết các hàm không đệ quy duyệt cây theo thứ tự inorder và postorder. inorder và postorder. Hãy đưa ra cách biểu diễn cây bởi mảng. Bằng cách sử dụng ngăn xếp.

Sign up to vote on this title
UsefulNot useful