+ Giải tất cả các bài toán cơ sở (thông thường rất dễ) , lưu các lời giải 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 các bài toán nhỏ đã lưu trong bảng [r]
Trang 1TRẠI HÈ PHƯƠNG NAM LẦN IV - 2017
KỶ YẾU HỘI THẢO
MÔN: TIN HỌC TRƯỜNG THPT CHUYÊN PHAN NGỌC HIỂN
Trang 2MỤC LỤC
1 Thuật toán tham lam
THPT Chuyên Thủ Khoa Nghĩa, An Giang
Thuật toán xác định hướng của một điểm so với một vector và
những ứng dụng trong việc giải bài toán hình học
Đoàn Minh Đức THPT Chuyên Bến Tre
47
4 Xác định thuật toán FLOYD – WARSHALL cho đồ thị dày
THPT Chuyên Vị Thanh, Hậu Giang 55
Trang 312 Chuyên đề Hình Học
THPT Chuyên Nguyễn Bỉnh Khiêm, Vĩnh Long
245
13 BINARY INDEX TREE BIT
THPT Chuyên Hùng Vương, Bình Dương
267
14
BINARY HEAP
Phạm Ngọc Bách THPT Chuyên Hoàng Lê Kha, Tây Ninh
Trang 4PHƯƠNG PHÁP THAM LAM
Trường THPT Chuyên Thủ Khoa Nghĩa – An Giang
I Ý tưởng của thuật toán tham lam:
Trong mọi khía cạnh của cuộc sống hàng ngày, công việc và nghiên cứu, con người phải luôn đối mặt với các bài toán để lựa chọn phương án có thể chấp nhận được Trong số những bài toán đó, có những bài toán chỉ đơn giản là cần có một giải pháp nhưng cũng có những bài toán khắt khe hơn, đòi hỏi không chỉ là một giải pháp
mà giải pháp đó còn phải là giải pháp tốt nhất (nhanh nhất, đơn giản nhất, hiệu quả nhất ) đó được gọi là những bài toán tối ưu Các bài toán tối ưu thường là một số rất lớn nghiệm, việc tìm ra nghiệm tối ưu đòi hỏi rất nhiều thời gian
Ý tưởng phương pháp tham lam là một trong những hướng suy nghĩ được sử dụng phổ biến trong những tình huống này Các thuật toán sử dụng phương pháp tham lam như nền tảng logic để tiếp cận, giải quyết bài toán được gọi là các thuật toán tham lam Các thuật toán ứng dụng phương pháp tham lam thường diễn ra qua nhiều giai đoạn và tại mỗi giai đoạn chúng ta thường không biết thông tin toàn bộ dữ liệu của cả quá trình mà chỉ biết tình trạng hiện tại và thông tin cho bước đi kế tiếp Ý tưởng chính của phương pháp tham lam là chúng ta không cần quan tâm tới dữ liệu tổng thể mà chỉ
từ những dữ liệu tại từng giai đoạn để chọn ra giải pháp tối ưu tại mỗi giai đoạn đó với
hy vọng là tổng hợp những giải pháp tối ưu cục bộ sẽ mang lại một giải pháp tối ưu cho tổng thể Từ ý tưởng đó cho thấy, kết quả có được từ thuật toán tham lam chỉ mang tính tối ưu tương đối, thông thường giải pháp cuối cùng có thể chưa là tối ưu mà chỉ là tiệm cận với phương án tối ưu Tuy nhiên với những điều kiện, thông tin thường không mấy rõ ràng của đầu vào, và cách tiếp cận vấn đề khá “trong sáng” của mình, phương pháp tham lam thường đưa ra giải pháp tương đối tốt trong giới hạn có thể chấp nhận và đặc biệt có tốc độ tính toán nhanh (giảm độ phức tạp tính toán của các thuật toán) Các thuật toán tham lam nói chung là đơn giản và hiệu quả (vì các tính toán để tìm ra quyết định tối ưu địa phương thường là đơn giản) Tuy nhiên, các thuật toán tham lam có thể không tìm được nghiệm tối ưu mà cho ra nghiệm tiệm cận tối ưu (nghiệm tương đối tốt), nhưng thông thường lại giúp giảm độ phức tạp thuật toán của các thuật toán một cách đáng kể Bên cạnh đó cũng có nhiều thuật toán được thiết kế
Trang 5theo kỹ thuật tham lam vẫn cho ta nghiệm tối ưu, chẳng hạn thuật toán Dijkstra tìm đường đi ngắn nhất từ một đỉnh tới các đỉnh còn lại trong đồ thị định hướng, các thuật toán Prim và Kruskal tìm cây bao trùm ngắn nhất trong đồ thị vô hướng
Lược đồ tổng quát của thuật toán tham lam:
II Một số bài toán được giải quyết bằng phương pháp tham lam:
1 Bài toán cái ba lô
a Phát biểu bài toán
Có n vật, mỗi vật i, i∈{1, ,n} được đặc trưng bởi
trọng lượng w i và giá trị v i Có một ba lô có khả năng
mang được trọng lượng m Giả sử w i , v i , m ∈N*
∀i∈{1, ,n} Hãy chọn vật xếp vào ba lô sao cho ba lô
thu được có giá trị nhất
Dữ liệu: Vào từ file BAG.INP có dạng:
- Dòng đầu tiên gồm n và m cách nhau ít nhất
một dấu cách
- n dòng tiếp theo, mỗi dòng thứ i cho biết trọng lượng và giá trị của vật thứ i
Kết quả: Ghi vào file BAG.OUT có dạng:
- Dòng đầu tiên ghi giá trị tối ưu của bài toán
Bài toán cái ba lô
Trang 6- n dòng tiếp theo, mỗi dòng cho biết số thứ tự của đồ vật và số lượng lấy của đồ
b Phân tích và thiết kế thuật toán
Ý tưởng: Ở đây, ta cần quan tâm đến yếu tố “đơn giá” của từng loại đồ vật, tức là
tỉ lệ giá trị/trọng lượng, đơn giá càng cao thì đồ càng quý Từ đó ta có kỹ thuật tham lam áp dụng cho bài toán này là:
- Bước 1: Tính đơn giá cho các loại đồ vật
- Bước 2: Sắp xếp các loại đồ vật theo đơn giá từ lớn đến nhỏ
- Bước 3: Xét các đồ vật theo thứ tự đã sắp xếp, với mỗi đồ vật được xét sẽ lấy số lượng tối đa mà trọng lượng còn lại của ba lô cho phép
- Bước 4: Xác định trọng lượng còn lại của ba lô và quay lại bước 3 cho đến khi xét hết các đồ vật hoặc trọng lượng còn lại của ba lô là 0
Minh họa với dữ liệu ở test 1:
Bước 1: Tính đơn giá cho các đồ vật, ta được bảng sau:
Trang 7Loại đồ vật Trọng lượng w Giá trị v Đơn giá c
Bước 2: Sắp xếp lại các đồ vật theo thứ tự từ lớn đến bé, ta có bảng sau:
Loại đồ vật Trọng lượng w Giá trị v Đơn giá c
+ Với m = 3, xét đồ vật 4, ta không thể lấy đồ vật 4 do vượt quá trọng lượng còn
lại của cái ba lô
+ Với m = 3, xét đồ vật 1, ta có thể lấy số lượng là 1 Khi đó m được tính lại là m
= 3 – 3 = 0
+ Do trọng lượng còn lại của ba lô là 0 nên dừng thuật toán
Vậy ta lấy được đồ vật 2, 1 với số lượng lần lượt tương ứng là 2, 1 với giá trị tối
ưu là 15
Nhận xét:
Với thuật toán tham lam, trong một số trường hợp ta chỉ tìm được phương án đủ
“tốt” tiệm cận với phương án tối ưu Điều đáng lưu tâm ở đây là một số bài toán tối ưu
tổ hợp có thuật toán tìm nghiệm chính xác đòi hỏi thời gian mũ, khi dữ liệu bài toán lớn thì rất khó áp dụng Trong trường hợp này ta sử dụng thuật toán tham lam cho
Trang 8nghiệm đủ tốt mà thời gian thực hiện rất nhanh, đây cũng chính là lý do tại sao thuật toán tham lam được mọi người quan tâm
Với 3 bộ test đã cho, ta tìm được nghiệm tối ưu ở 2 test đầu, test thứ 3 không cho được nghiệm tối ưu Muốn tìm được nghiệm tối ưu, ta dùng phương pháp quy hoạch động cho bài toán này
Độ phức tạp thuật toán: Quá trình sắp xếp nếu làm theo QuickSort mất
O(nlog(n)), quá trình lặp n đồ vật mất O(n) Vậy tổng độ phức tạp của thuật toán là O(nlog(n))
2 Bài toán Chọn hoạt động
a Phát biểu bài toán
Chúng ta có rất nhiều nhiệm vụ trong ngày Giả sử có 𝑛 nhiệm vụ và nhiệm vụ thứ 𝑖 phải bắt đầu ngay sau thời điểm 𝑠𝑖, thực hiện liên tục và kết thúc tại thời điểm f i
Có thể coi mỗi nhiệm vụ tương ứng với một khoảng thời gian thực hiện(𝑠𝑖, fi] Hãy chọn ra nhiều nhất các nhiệm vụ để làm, sao cho không có thời điểm nào chúng ta phải làm hai nhiệm vụ cùng lúc, hay nói cách khác, khoảng thời gian thực hiện hai nhiệm
vụ bất kỳ là không giao nhau
Dữ liệu: Vào từ file AS.INP có dạng:
- Dòng đầu tiên là số
- dòng tiếp theo, dòng thứ cho biết chứa hai số nguyên
Kết quả: Ghi vào file AS.OUT có dạng:
- Dòng đầu tiên ghi số hoạt động được chọn
- Ḍng tiếp theo cho biết hoạt động được chọn
Trang 9Gọi i 1 là nhiệm vụ kết thúc sớm nhất Với một phương án tối ưu bất kỳ, giả sử
thứ tự các nhiệm vụ cần thực hiện trong phương án tối ưu đó là (j 1, j2, …, jk ) Do i 1 là
nhiệm vụ kết thúc sớm nhất nên chắc chắn nó không thể kết thúc muộn hơn j 1, vì vậy
việc thay j 1 bởi i 1 trong phương án này sẽ không gây ra sự xung đột nào về thời gian thực hiện các nhiệm vụ Sự thay thế này cũng không làm giảm bớt số lượng nhiệm vụ
thực hiện được trong phương án tối ưu, nên (i 1, j2, …, jk) cũng sẽ là một phương án tối
ưu Yêu cầu của bài toán là chỉ cần đưa ra một phương án tối ưu, vì thế ta sẽ chỉ ra phương án tối ưu có nhiệm vụ đầu tiên là nhiệm vụ kết thúc sớm nhất trong số 𝑛 nhiệm vụ Điều này có nghĩa là chúng ta không cần thử 𝑛 khả năng chọn nhiệm vụ đầu tiên, đi giải các bài toán con, rồi mới đánh giá chúng để đưa ra quyết định cuối cùng
Chúng ta sẽ đưa ngay ra quyết định tức thời: chọn ngay nhiệm vụ kết thúc sớm nhất i 1
làm nhiệm vụ đầu tiên
Sau khi chọn nhiệm vụ i 1, bài toán lớn quy về bài toán con: Chọn nhiều nhiệm
vụ nhất trong số các nhiệm vụ được bắt đầu sau khi i 1 kết thúc Phép chọn tham lam lại cho ta một quyết định tức thời: nhiệm vụ tiếp theo trong phương án tối ưu sẽ là nhiệm
vụ bắt đầu sau thời điểm f[i 1] và có thời điểm kết thúc sớm nhất, gọi đó là nhiệm vụ i2
Trang 10Và cứ như vậy chúng ta chọn tiếp các nhiệm vụ i 3, i4… Cứ như vậy cho tới khi không còn nhiệm vụ nào chọn được nữa
Đến đây ta có thể thiết kế một thuật toán tham lam như sau:
Sắp xếp các nhiệm vụ theo thứ tự không giảm của thời điểm kết thúc
Khởi tạo thời điểm 𝐹𝑖𝑛𝑖𝑠ℎ𝑇𝑖𝑚𝑒 ∶= 0
Duyệt các nhiệm vụ theo danh sách đã sắp xếp (nhiệm vụ kết thúc sớm sẽ được xét trước nhiệm vụ kết thúc muộn), nếu xét đến nhiệm vụ 𝑖 có [𝑖] ≥ 𝐹𝑖𝑛𝑖𝑠ℎ𝑇𝑖𝑚𝑒 thì chọn ngay nhiệm vụ 𝑖 vào phương án tối ưu và cập nhật 𝐹𝑖𝑛𝑖𝑠ℎ𝑇𝑖𝑚𝑒 thành thời điểm kết thúc nhiệm vụ 𝑖: 𝐹𝑖𝑛𝑖𝑠ℎ𝑇𝑖𝑚𝑒 ≔ 𝑓[𝑖]
Minh họa với dữ liệu test 1:
Ta có bảng dữ liệu sau khi sắp xếp là:
FinishTime = 0
Với bảng trên, ta chọn công việc 3 trước, khi đó cập nhật lại FinishTime= 3
Tiếp tục duyệt các công việc còn lại, công việc 4 sẽ không được chọn do
s[4]< FinishTime
Ta chọn công việc 5 do s[5] FinishTime, cập nhật lại FinishTime = 7
Công việc 2 không được chọn do s[4]< FinishTime
Ta chọn công việc 1 do s[1] FinishTime, cập nhật lại FinishTime = 9
Dừng thuật toán lại vì đã xét hết các công việc
Hình 0.1 Minh họa bài toán Chọn hoạt động
Nhận xét: Thuật toán tham lam cho bài toán này luôn cho ra phương án tối ưu
Trang 11Độ phức tạp thuật toán: Dễ thấy rằng ở thủ tục GreedySelection được thực
hiện trong thời gian O(n) Thời gian mất chủ yếu nằm ở thuật toán sắp xếp các công
việc theo thời điểm kết thúc Như đoạn code ở trên, ta dùng QuickSort, do đó độ phức
tạp thuật toán sẽ là O(nlog(n))
3 Bài toán máy rút tiền tự động ATM
a Phát biểu bài toán
Một máy ATM hiện có n (n < 20) tờ tiền có mệnh giá t 1, t2, , tn Hãy tìm cách trả
ít tờ nhất với số tiền đúng bằng s
Dữ liệu: Vào từ file ATM.INP có dạng:
- Dòng đầu tiên gồm n và s cách nhau ít nhất một dấu cách
- Dòng thứ 2 gồm n số t 1, t2, …, tn
Kết quả: Ghi vào file ATM.OUT, nếu không có phương án thì ghi -1, ngược lại
thì:
- Dòng đầu tiên ghi số tờ tiền
- Dòng tiếp theo ghi cách trả tiền
b Phân tích và thiết kế thuật toán
Ý tưởng: Như đã phân tích ở ví dụ 1.2, ta thiết kế thuật toán tham lam như sau:
tại mỗi bước ta sẽ chọn tờ tiền lớn nhất còn lại không vượt quá lượng tiền còn phải trả,
cụ thể:
Bước 1: Sắp xếp các tờ tiền giảm dần theo giá trị
Trang 12Bước 2: Lần lượt xét các tờ tiền từ giá trị lớn đến giá trị nhỏ, nếu vẫn còn chưa lấy đủ s và tờ tiền đang xét có giá trị nhỏ hơn hoặc bằng s thì lấy luôn tờ tiền đó
Minh họa với dữ liệu ở test 1:
Bước 1: Sau khi sắp xếp các tờ tiền giảm dần theo giá trị, ta có:
200 100 100 50 50 50 50 20 20 10
Bước 2: Với tiền cần rút là 390, ta chọn được 2 phần tử đầu tiên trong dãy, khi đó
số tiền cần rút còn lại là 90 Do đó ta không chọn tờ 100, mà sẽ xét tiếp phần tử tiếp theo Ta chọn được một tờ 50, tiền cần rút còn lại là 40 Vì vậy ta không chọn được các tờ 50 Xét tiếp ta chọn được hai tờ 20, khi đó đã đủ số tiền cần rút, dừng thuật toán Kết quả là ta nhận được là 200 100 50 20 20
Nhận xét:
Với bộ test 1, thuật toán tham lam cũng cho được nghiệm tối ưu Tuy nhiên với
bộ test 2, thuật toán tham lam không cho nghiệm tối ưu và bộ test 3 thì thuật toán tham lam không tìm được nghiệm mặc dù có nghiệm
Độ phức tạp thuật toán: Thuật toán tham lam qua một lần duyệt, có độ phức tạp
là O(n) Toàn bộ quá trình mất thời gian nhiều nhất là ở quá trình sắp xếp, ở đây ta sắp xếp theo phương pháp chọn, có độ phức tạp là O(n 2 ) Vậy độ phức tạp của thuật toán
là O(n 2 )
4 Bài toán băng nhạc
a Phát biểu bài toán
Người ta cần ghi n bài hát, được mã số từ 1 đến n, vào một băng nhạc có thời
lượng tính theo phút đủ chứa toàn bộ các bài hát đã cho Với mỗi bài hát ta biết thời lượng phát của mỗi bài hát đó Băng sẽ được lắp vào một máy phát nhạc đặt trong một siêu thị Khách hàng muốn nghe bài hát nào chỉ cần nhấn phím tương ứng với bài hát
đó Để tìm và phát bài hát thứ i trên băng, máy xuất phát từ đầu cuộn băng, quay băng
để bỏ qua i-1 bài ghi trước đó Thời gian quay băng bỏ qua mỗi bài hát và thời gian
phát bài hát đó được tính là như nhau Tính trung bình, các bài hát trong một ngày được khách hàng lựa chọn với số lần (tần suất) là như nhau Hãy tìm cách ghi các bài trên băng sao cho tổng thời gian quay băng trong mỗi ngày là ít nhất
Trang 13Dữ liệu: Vào từ file CASSETTE.INP có dạng:
- Dòng đầu tiên là số tự nhiên n cho biết số lượng bài hát
- Dòng thứ 2 gồm n số nguyên dương thể hiện dung lượng tính theo phút của mỗi
bài, mỗi số cách nhau một dấu cách
Kết quả: Dữ liệu ghi vào file CASSETTE.OUT có dạng:
- n dòng đầu tiên thể hiện trật tự ghi bài hát trên băng, mỗi dòng gồm hai số nguyên dương j và d cách nhau bởi một dấu cách, trong đó j là số thứ tự của bài hát cần ghi, d là thời gian tìm và phát bài đó theo trật tự này
- Dòng thứ n+1 ghi tổng số thời gian quay băng nếu mỗi bài hát được phát một
Trang 14Minh họa với dữ liệu đã cho:
Rất đơn giản, ta chỉ cần sắp xếp theo thứ tự không giảm thời gian phát của từng bài nhạc Với dữ liệu đã cho ta sẽ có thứ tự là 2, 3, 1 và thời gian phát toàn bộ sẽ được
tính là 2 + (2 + 3) + (2 + 3 + 7) = 19 phút
Nhận xét:
Thuật toán tham lam trong trường hợp này là các thời gian phát của mỗi bài nhạc được tính theo trật tự tăng dần Lời giải tìm được sẽ là lời giải tối ưu
Độ phức tạp thuật toán: Thuật toán tham lam qua một lần duyệt, có độ phức tạp
là O(n) Toàn bộ quá trình mất thời gian nhiều nhất là ở quá trình sắp xếp, ở đây ta sắp xếp theo QuickSort, có độ phức tạp là O(nlog(n)) Vậy độ phức tạp của thuật toán là O(nlog(n))
5 Bài toán nối điểm đen trắng
a Phát biểu bài toán
Trên trục số thực cho n điểm đen và n điểm trắng hoàn toàn phân biệt Các điểm đen có tọa độ nguyên a 1, a2, …, an còn các điểm trắng có tọa độ nguyên b 1, b2, …, bn
Người ta muốn chọn ra k điểm đen và k điểm trắng để nối mỗi một điểm đen với một điểm trắng sao cho k đoạn thẳng tạo được đôi một không có điểm chung
Yêu cầu: Cho tọa độ của n điểm đen a 1, a2, …, an và tọa độ của điểm trắng b 1, b2,
…, bn Hãy tìm giá trị k lớn nhất thỏa mãn yêu cầu trên [7]
Dữ liệu: Vào từ file BAW.INP có dạng:
- Dòng thứ nhất chứa số nguyên dương n (0 < n ≤ 105)
- Dòng thứ hai chứa các số a 1, a2, …, an (|ai| <= 109, i = 1, 2,…, n)
Trang 15- Dòng thứ ba chứa các số b 1, b2, …, bn (|bi| <= 109, i = 1, 2,…, n)
Các số trên cùng một dòng được ghi cách nhau ít nhất một dấu cách
Kết quả: Ghi ra một số nguyên duy nhất là số k lớn nhất tìm được
b Phân tích và thiết kế thuật toán
Hình 0.2 Minh họa dữ liệu bài toán nối điểm đen trắng
Ý tưởng:
Trộn hai màu lại thành một danh sách trên trục tọa độ và sắp xếp lại theo thứ tự tăng dần Dùng ý tưởng tham lam duyệt thứ tự từ trái sang phải, nếu thấy hai cặp liền nhau khác màu thì tăng biến đếm lên 1, bởi vì nhận thấy rằng cần chọn các cặp điểm
kề nhau khác màu trên trục này thì sẽ được nhiều cặp điểm không giao nhau Ta cũng chú ý là tăng bước nhảy để tránh trường hợp 1 điểm đen (trắng) kẹp giữa 2 điểm trắng (đen) thì tính thành 2 đoạn vì ở đây đề bài nói là các điểm đen trắng phân biệt
Minh họa với dữ liệu đã cho:
Theo đề bài ta có các biến và các giá trị như sau:
Trang 16Thêm tất cả các giá trị của mảng b thêm sau mảng a, đồng thời ở các vị trí thêm
đó ở mảng color ta đánh dấu là 1 (để phân biệt với các phần tử của mảng a) Ta có
Nhận xét: Thuật toán tham lam thể hiện ở chỗ sau khi sắp xếp dữ liệu, ta chỉ
cần chọn các cặp điểm liền kề nhau khác màu trên trục là sẽ ra được kết quả tối ưu
Độ phức tạp thuật toán: Thuật toán tham lam qua một lần duyệt n phần tử có
O(n), sắp xếp dùng QuickSort có O(nlog(n)) Vậy độ phức tạp của thuật toán là O(nlog(n))
Trang 17QUY HOẠCH ĐỘNG
Nguyễn Chánh Tín - THPT Chuyên Bạc Liêu
Phần 1: CƠ SỞ LÝ THUYẾT
I- CƠ SỞ LÝ THUYẾT:
1) Phương pháp quy hoạch động:
Nhà toán học Richard Bellman đã phát minh phương pháp Quy hoạch động vào
năm 1953 Ngành này đã được thành lập như là một chủ đề về kỹ nghệ và phân tích hệ thống đã được tổ chức IEEE (Viện kỹ nghệ Điện và Điện tử quốc tế) thừa nhận
Phương pháp quy hoạch động dùng để giải bài toán tối ưu có tính 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 một số hữu hạn các bài toán con Đối với nhiều thuật toán đệ quy, nguyên lý chia
để trị (devide and conquer) 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ó thành nhiều bài toán con cùng dạng với nó
để có thể 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 bài những 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 đệ quy và cũng là nội dung Phương pháp quy hoạch động:
+ Đệ 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 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 con nhỏ hơn và lại đi giải quyết 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)
Sau đây ta sẽ xét một ví dụ đơn giản và rất quen thuộc:
Ví dụ: Dãy Fibonacci là dãy số nguyên dương được định nghĩa như sau:
F[1]=F[2]=1;
Với mọi i: 3<=i: F = F[i-1] + F[i-2]
Trang 18Cách 2 thì không như vậy 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 rằng mỗi giá trị Fibonnaci chỉ phải
tính 1 lần
(Cách 2 còn có thể cải tiến thêm nữa, chỉ cần dùng 3 biến tính lại giá trị lẫn nhau)
Trước khi áp dụng phương pháp quy hoạch động ta phải xét xem phương pháp
đó có thỏa mãn những yêu cầu dưới đây hay không:
Trang 19+ Bài toán lớn phải phân rã được thành nhiều bài toán con, mà sự phối hợp lời giải của các bài toán con đó cho ta lời giải của bài toán lớn
+ Vì quy hoạch động là đi giải tất cả các bài toán con, nên nếu không đủ không gian vật lý lưu trữ lời giải (bộ nhớ, đĩa,…) để 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
+ 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
+ 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
3) Các bước cài đặt một chương trình sử dụng quy hoạch động:
+ Giải tất cả các bài toán cơ sở (thông thường rất dễ), lưu các lời giải 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 các 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 Cho tới khi bài toán ban đầu tìm được lời giải
+ Dựa vào bảng phương án, truy vết tìm ra nghiệm tối ưu
Cho đến nay, vẫn chưa có một định lý nào cho biết một cách chính xác những bài toán nào có thể giải quyết hiệu quả bằng quy hoạch động Tuy nhiên để biết được bài
toán có thể giải bằng quy hoạch động hay không, ta có thể tự đặt câu hỏi : “Một nghiệm tối ưu của bài toán lớn có phải là sự phối hợp các nghiệm tối ưu của các bài toán con hay không?” và “Liệu có thể nào lưu trữ được nghiệm các bài toán con dưới một hình thức nào đó để phối hợp tìm được nghiệm bài toán lớn”
Trang 20Cuối cùng trước khi khảo sát một số bài toán quy hoạch động, ta nhắc lại: Phương pháp tốt nhất để giải quyết mọi bài toán trong tin học là biết sử dụng và phối hợp uyển chuyển nhiều thuật toán, không được lạm dụng hay coi thường bất cứ một phương pháp nào
II- MỘT SỐ BÀI TOÁN VÍ DỤ ĐIỂN HÌNH:
1) Bài 1: Trước tiên chúng ta hãy xét 1 bài toán thật đơn giản và quen thuộc đó là
tìm giá trị lớn nhất trong n số là a1, a2, , an Giải quyết bài toán này, ta sẽ xây dựng các cấu hình con tối ưu bằng cách lần lượt tìm số lớn nhất trong k số đầu tiên với k
If a[k]>max then max:=a[k];
Write('Gia tri lon nhat cua day cac so da cho la: ',max);
Readln
End
Trang 21Bây giờ chúng ta xét đến bài toán 2 có phần hấp dẫn hơn Đây chắnh là một trong những bài toán kinh điển cho giải thuật qui hoạch động:
2) Bài 2: BÀI TOÁN XẾP BA LÔ (một số sách ghi là bài toán cái túi, tương tự như bài toán xếp vali) là một bài toán tối ưu hóa tổ hợp Bài toán được đặt tên từ vấn
đề chọn những gì quan trọng có thể nhét vừa vào trong một cái túi (với giới hạn khối lượng) để mang theo trong một chuyến đi
Một số cách phát biểu nội dung bài toán:
Một kẻ trộm đột nhập vào một cửa hiệu tìm thấy
có n mặt hàng có trọng lượng và giá trị khác nhau, nhưng
hắn chỉ mang theo một cái túi có sức chứa về trọng lượng tối
đa là M Vậy kẻ trộm nên bỏ vào ba lô những món nào và số
lượng bao nhiêu để đạt giá trị cao nhất trong khả năng mà
hắn có thể mang đi được
Một hành khách chỉ được mang theo một vali có khối
lượng hàng hoá tối đa là M Hành khách đó đã chuẩn bị ra N dồ vật được đánh số từ 1 đến N để chuẩn bị mang theo Đồ vật thứ i có trọng lượng là ai và giá trị sử dụng là
ci (i = 1, 2, N) Yêu cầu: Chỉ ra đồ vật mà hành khách đó cần mang theo sao cho tổng giá trị sử dụng là lớn nhất?
* Bài toán:
Trong siêu thị có n gói hàng (n ≤ 100), gói hàng thứ i có trọng lượng là Wi ≤ 100
và trị giá Vi ≤ 100 Một tên trộm đột nhập vào siêu thị, tên trộm mang theo một cái túi
có thể mang được tối đa trọng lượng M ( M ≤ 100) Hỏi tên trộm sẽ lấy đi những gói hàng nào để được tổng giá trị lớn nhất
Input: file văn bản BAG.INP
Ớ Dòng 1: Chứa hai số n, M cách nhau ắt nhất một dấu cách
Ớ n dòng tiếp theo, dòng thứ i chứa hai số nguyên dương Wi, Vi cách nhau ắt nhất một dấu cách
Output: file văn bản BAG.OUT
Ớ Dòng 1: Ghi giá trị lớn nhất tên trộm có thể lấy
Ớ Dòng 2: Ghi chỉ số những gói bị lấy
Trang 22Nếu gọi F[i, j] là giá trị lớn nhất có thể có bằng cách chọn trong các gói {1, 2,
…, i} với giới hạn trọng lượng j Thì giá trị lớn nhất khi được chọn trong số n gói với giới hạn trọng lượng M chính là F[n, M]
Công thức truy hồi tính F[i, j]
Với giới hạn trọng lượng j, việc chọn tối ưu trong số các gói {1, 2, …,i – 1, i} để
có giá trị lớn nhất sẽ có hai khả năng:
• Nếu không chọn gói thứ i thì F[i, j] là giá trị lớn nhất có thể bằng cách chọn trong số các gói {1, 2, …, i – 1} với giới hạn trọng lượng là j Tức là
F[i, j] = F[i - 1, j]
• Nếu có chọn gói thứ i (tất nhiên chỉ xét tới trường hợp này khi mà Wi ≤ j) thì F[i, j] bằng giá trị gói thứ i là Vi cộng với giá trị lớn nhất có thể có được bằng cách chọn trong số các gói {1, 2, …, i – 1} với giới hạn trọng lượng j – Wi Tức là về mặt giá trị thu được:
F[i, j] = Vi + F[i - 1, j - Wi]
Vì theo cách xây dựng F[i, j] là giá trị lớn nhất có thể, nên F[i, j] sẽ là max trong
2 giá trị thu được ở trên
Cơ sở quy hoạch ðộng:
Dễ thấy F[0, j] = giá trị lớn nhất có thể bằng cách chọn trong số 0 gói = 0
Tính bảng phương án:
Trang 23Bảng phương án F gồm n + 1 dòng, M + 1 cột, trước tiên được điền cơ sở quy hoạch động: Dòng 0 gồm toàn số 0 Sử dụng công thức truy hồi, dùng dòng 0 tính dòng 1, dùng dòng 1 tính dòng 2, v.v… đến khi tính hết dòng n
Truy vết:
Tính xong bảng phương án thì ta quan tâm đến F[n, M] đó chính là giá trị lớn nhất thu được khi chọn trong cả n gói với giới hạn trọng lượng M Nếu F[n, M] = F[n -
1, M] thì tức là không chọn gói thứ n, ta truy tiếp F[n - 1, M] Còn nếu F[n, M] ≠ F[n -
1, M] thì ta thông báo rằng phép chọn tối ưu có chọn gói thứ n và truy tiếp F[n - 1, M - Wn] Cứ tiếp tục cho tới khi truy lên tới hàng 0 của bảng phương án
Trang 24for j := 0 to m do
begin {tinh f[i, j]}
f[i, j] := f[i - 1, j]; {Neu khong chon goi thu i}
if (j>= w[i]) and (f[i, j] < f[i-1, j-w[i]]+v[i]) then
f[i, j] := f[i-1, j-w[i]]+v[i];
end;
end;
procedure trace; {truy vet tim nghiem toi uu}
begin
writeln(f[n, m]); {in ra gia tri lon nhat co the tim duoc}
while n <> 0 do {truy vet tu hang n len hang 0}
assign(input, 'bag.inp'); reset(input);
assign(output, 'bag.out'); rewrite(output);
Trang 253) Bài 3: DÃY CON ĐƠN ĐIỆU TĂNG DÀI NHẤT
Bài toán: Cho dãy số nguyên A = a1, a2, Ầ, an (n ≤ 10000, -10000 ≤ ai ≤ 10000) Một dãy con của A là một cách chọn ra trong A một số phần tử giữ nguyên thứ tự Như vậy A có 2n dãy con
Yêu cầu: Tìm dãy con đơn điệu tăng của A có độ dài lớn nhất
Vắ dụ: A = (1, 2, 3, 4, 9, 10, 5, 6, 7, 8) Dãy con đơn điệu tăng dài nhất là: (1, 2,
3, 4, 5, 6, 7, 8)
* Dữ liệu (Input) vào từ file văn bản INCSEQ.INP
Ớ Dòng 1: Chứa số n
Ớ Dòng 2: Chứa n số a1, a2, Ầ, an cách nhau ắt nhất một dấu cách
* Kết quả (Output) ghi ra file văn bản INCSEQ.OUT
Ớ Dòng 1: Ghi độ dài dãy con tìm được
Ớ Các dòng tiếp: ghi dãy con tìm được và chỉ số những phần tử được chọn vào dãy con đó
* Ý týởng giải thuật:
Bổ sung vào A hai phần tử: a0 = -∞ và an+1 = +∞ Khi đó dãy con đơn điệu tăng dài nhất chắc chắn sẽ bắt đầu từ a0 và kết thúc ở a n+1
Trang 26Với mọi i: 0 ≤ i ≤ n + 1 Ta sẽ tính L[i] = độ dài dãy con đơn điệu tăng dài nhất bắt đầu tại ai
Cơ sở quy hoạch ðộng (bài toán nhỏ nhất):
L[n+1] = Độ dài dãy con đơn điệu tăng dài nhất bắt đầu tại an+1 = +∞ Dãy con này chỉ gồm mỗi một phần tử (+∞) nên L[n+1]=1
Công thức truy hồi: Giả sử với i từ n đến 0, ta cần tính L[i]: độ dài dãy con tăng
dài nhất bắt đầu tại ai L[i] được tính trong điều kiện L[i + 1], L[i + 2], …, L[n + 1] đã biết:
Dãy con đơn điệu tăng dài nhất bắt đầu từ ai sẽ được thành lập bằng cách lấy ai ghép vào đầu một trong số những dãy con đơn điệu tăng dài nhất bắt đầu tại vị trí aj đứng sau ai Ta sẽ chọn dãy nào để ghép ai vào đầu? Tất nhiên là chỉ được ghép ai vào đầu những dãy con bắt đầu tại aj nào đó lớn hơn ai (để đảm bảo tính tăng) và dĩ nhiên
ta sẽ chọn dãy dài nhất để ghép ai vào đầu (để đảm bảo tính dài nhất) Vậy L[i] được
tính như sau: Xét tất cả các chỉ số j trong khoảng từ i + 1 ðến n + 1 mà a j >a i , chọn
ra chỉ số jmax có L[jmax] lớn nhất Ðặt L[i] := L[jmax] + 1
Truy vết: Tại bước xây dựng dãy L, mỗi khi tính L[i] = L[jmax] + 1, ta đặt T[i]
= jmax Để lưu lại rằng: Dãy con dài nhất bắt đầu tại ai sẽ có phần tử thứ hai kế tiếp là
ajmax
Sau khi tính xong hay dãy L và T, ta bắt đầu từ 0
T[0] là phần tử đầu tiên được chọn,
Trang 27L[n + 1] := 1; {Dien co so quy hoach dong}
for i := n downto 0 do {Tinh bang phuong an}
Trang 284) Bài 4: BÀI TOÁN TÌM XÂU CON CHUNG DÀI NHẤT
Bài toán: Cho hai xâu X =x1x2…xm và Y=y 1y2…yn Tìm xâu Z = z 1z2…zk là xâu con chung dài nhất của X và Y Một xâu con của xâu A là một cách chọn trong A một
số phần tử giữ nguyên thứ tự
* Ý tưởng giải thuật:
Bảng phương án:
Ta sẽ dùng mảng hai chiều B[0 m, 0 n] làm bảng phương án, trong đó B[i,j] là
độ dài xâu chung dài nhất của các xâu con Xi (phần đầu của X) và Yj (phần đầu của Y)
Cơ sở: Rõ ràng nếu ít nhất một trong hai xâu X hoặc Y là xâu rỗng (j=0 hoặc
i=0) thì B[i,j]=0
Công thức truy hồi: Dễ dàng có các nhận xét sau:
- Nếu i,j > 0 và xi=yi thì B[i,j] = B[i-1,j-1] + 1
- Nếu i,j > 0 và xi<>yj thì B[i,j] = max ( B[i,j-1], B[i-1,j] )
Truy vết :
Như vậy B[n,m] cho biết độ dài của xâu con chung dài nhất Để chi ra tường minh xâu con chung dài nhất ta cần xây dựng bảng T[1 m, 1 n] để ghi nhận truy vết đánh dấu B[i,j] được tính từ B[i-1,j-1] hay B[i,j-1] hay B[i-1,j]
Chương trình:
const fi='xaucon.inp';
fo='xaucon.out';
var s1,s2,s:string;
Trang 315) Bài 5: BÀI TOÁN XÂU CON ĐỐI XỨNG DÀI NHẤT
Bài toán: Một xâu được gọi là đối xứng (palindrome) nếu như khi đọc xâu này
từ phải sang trái cũng thu được xâu ban đầu
Yêu cầu: tìm một xâu con đối xứng dài nhất của một xâu s cho trước Xâu con là xâu thu được khi xóa đi một số ký tự từ xâu ban đầu
* Dữ liệu vào: Gồm một dòng duy nhất chứa xâu S, chỉ gồm những chữ cái in thường
* Kết quả: Gồm một dòng duy nhất là một xâu con đối xứng dài nhất của xâu S Nếu có nhiều kết quả, chỉ cần in ra một kết quả bất kỳ
Giới hạn: Xâu S có độ dài không vượt quá 2000
Ví dụ: Dữ liệu vào: lmevxeyzl Kết quả: level
2) Ý tưởng giải thuật:
Ta sẽ chuyển bài toán về một bài toán quy hoạch động cơ bản là: Bài toán tìm xâu con chung dài nhất
Với dữ liệu vào là S1
Ta tạo xâu S2 là xâu ngược của S1bằng cách chép các phần tử của xâu S1 vào xâu S2 theo thứ tự ngược lại
Sau đó ta sẽ tìm xâu con chung dài nhất của S1 và S2
Ta chỉ cần tìm xâu con chung dài nhất của một phần của S1 và nghịch đảo phần
còn lại, tức là ta chỉ xét một phần của bảng phương án với i+j<=chiều dài của S1
Ví dụ:
S1 = lmevxeyzl
Ta có bảng phương án (hình bên)
Trang 32Khi đó xâu con chung dài nhất là
le của S1 4 =“lmev” và S2 4=”lzye” (hoặcS1 3 =”lme” và S2 5=”lzyex”)
Khi ta truy vết để tìm xâu con chung ta sẽ kiểm tra xem xâu đối xứng của chúng
ta là lẻ hay chẵn (số kí tự)
+ Nếu i+j=chiều dài của S1, tức là 2 kí tự đối xứng đứng liên tiếp nhau trong S1,
vì vậy xâu đối xứng là chẵn
+ Ngược lại, tức là mọi i+j<chiều dài của S1, thì trong S1, có các kí tự xen giữa hai kí tự đối xứng, nên xâu đối xứng là lẻ Trong ví dụ trên thì có hai kí tự v và x xen
giữa xâu đối xứng
Với xâu đối xứng chẵn ta chỉ việc sao chép lại nửa sau dựa vào nửa đầu
Còn xâu lẻ ta sẽ chọn thêm một kí tự xen giữa Theo ví dụ trên, có thể
chọn v hoặc x Như vậy xâu đối xứng dài nhất sẽ là level hoặc lexel
Trang 346) Bài 6: BÀI TOÁN DI CHUYỂN TỪ TÂY SANG ĐÔNG
1) Bài toán: Cho một bảng A kắch thýớc m x n, trên đó ghi các số nguyên Một
người xuất phát tại ô nào đó của cột 1, cần sang cột n (tại ô nào cũng được) Quy tắc:
Từ ô A[i, j] chỉ được quyền sang một trong 3 ô A[i, j + 1]; A[i - 1, j + 1]; A[i + 1, j + 1] Hãy tìm vị trắ ô xuất phát và hành trình đi từ cột 1 sang cột n sao cho tổng các số
ghi trên đường đi là lớn nhất (nhỏ nhất)
Trang 35Dữ liệu vào: Từ file vãn bản dongtay.inp gồm:
- Dòng ðầu ghi hai số m, n (2<= m, n <=1000)
- Dòng thứ i trong m dòng tiếp theo mỗi dòng ghi n số là các số trong bảng ( |A[I,j]|<=1000)
Kết quả: file vãn bản dongtay.out gồm:
2) Ý tưởng giải thuật: Gọi B[i, j] là số điểm lớn nhất (nhỏ nhất) có thể có được
khi tới ô A[i, j] Rõ ràng đối với những ô ở cột 1 thì B[i, 1] = A[i, 1]:
Với những ô (i, j) ở các cột khác Vì chỉ những ô (i, j – 1), (i – 1, j – 1), (i + 1, j – 1) là có thể sang được ô (i, j), và khi sang ô (i, j) thì số điểm được cộng thêm A[i, j] nữa Chúng ta cần B[i, j] là số điểm lớn nhất có thể nên B[i, j] = max(B[i, j - 1], B[i -
1, j - 1], B[i + 1, j - 1]) + A[i, j] (Hoặc min) Ta dùng công thức truy hồi này tính tất cả
các B[i, j] Cuối cùng chọn ra B[i, n] là phần tử lớn nhất trên cột n của bảng B và từ đó truy vết tìm ra đường đi nhiều điểm nhất
* Chương trình:
const max = 2000000000;
Trang 36if b[i,j-1] < b[m,j-1] then m:=i;
if b[i+1,j-1] < b[m,j-1] then m:=i+1;
Trang 38close(input); close(output);
End
7) Bài 7: BÀI TOÁN CHIA KẸO:
Có N gói kẹo, gói thứ i có Ai cái kẹo Không được bóc bất kỳ một gói kẹo nào, 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
Dữ liệu vào trong file “chiakeo.inp” có dạng :
Dòng đầu tiên là số N (N<=100);
Dòng thứ hai là N số A i (i=1, 2, , N; Ai <=100)
Kết quả ra file “chiakeo.out” có dạng:
Dòng đầu là độ chênh lệch nhỏ nhất giữa hai phần có thể được
Dòng hai là một dãy N số, nếu s i =1 thì gói thứ i thuộc phần 1, nếu si =2 thì gói thứ i thuộc phần 2
* Lời giải:
- Với một số M bất kì, nếu ta biết được có tồn tại một cách chọn các gói kẹo để tổng số kẹo của các gói được chọn bằng đúng M không, thì bài toán được giải sẽ quyết Vì đơn giản là ta chỉ cần chọn số M sao cho M gần với S/2 nhất (với i
=1,2, ,N) Sau đó xếp các gói kẹo để tổng bằng M vào phần một, phần thứ hai sẽ gồm các gói kẹo còn lại
- Để kiểm tra được điều trên ta sẽ xây dựng tất cả các tổng có thể có của N gói kẹo bằng cách: ban đầu chưa có tổng nào được sinh ra
- Làm lần lượt với các gói kẹo từ 1 đến N, với gói kẹo thứ i, ta kiểm tra xem hiện tại có các tổng nào đã được sinh ra, giả sử các tổng đó là x1, x2, , xt vậy thì đến bước này sẽ có thể sinh ra các tổng x1, x2, , xt và Ai và x1+Ai,x2+Ai, ,xt+Ai
- Với N gói kẹo, mà mỗi gói có không quá 100 cái kẹo vậy tổng số kẹo không vượt quá N*100 ≤ 10000 cái kẹo Dùng mảng đánh dấu D, nếu có thể sinh được ra tổng bằng k thì D[k] = 1 ngược lại D[k] = 0
* Chương trình:
const max = 100;
fi = 'chiakeo.inp';
fo = 'chiakeo.out';
Trang 39var a,s : array[1 max]of integer;
Trang 408) Bài 8: DÃY CON CÓ TỔNG CHIA HẾT CHO K
Cho một dãy số nguyên A1, A2, , AN và một số k 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
Dữ liệu vào trong file “dayso.inp” có dạng: