Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
QUY HOẠCH ĐỘNG
Tổng quan
Quy hoạch động, giống như phương pháp “chia để trị”, giải quyết các bài toán
bằng cách kết hợp các giải pháp cho các bài toán con với nhau. (“Quy hoạch” trong
ngữ cảnh này nói đến một phương pháp biểu bảng, không phải là viết code máy tính.)
Như chúng ta thấy trong chương 2, các thuật toán “chia để trị” chia bài toán thành
nhiều bài toán con độc lập, giải quyết các bài toán này một bằng đệ quy, và sau đó kết
hợp các giải pháp của chúng lại để giải quyết bài toán gốc. Trong sự trái ngược, quy
hoạch động cũng có thể ứng dụng được khi các bài toán con là không độc lập với
nhau, điều đó xảy ra khi các bài toán con chia sẻ các bài toán con của các bài toán con.
Trong ngữ cảnh này, thuật toán “chia để trị” làm việc tốt hơn cả mức cần thiết, giải
quyết các bài toán con của các bài toán con lặp đi lặp lại nhiều lần. Một thuật toán quy
hoạch động giải quyết mọi bài toán con của bài toán con chỉ một lần và sau đó lưu lại
câu trả lời của nó vào trong một bảng, do đó ngăn chặn được công việc tính toán lại
câu trả lời mỗi khi bài toán con của bài toán con được bắt gặp.
Quy hoạch động điển hình là được ứng dụng cho các bài toán tối ưu. Như là các
bài toán mà nó có thể có nhiều giải pháp có khả năng. Mỗi giải pháp có một giá trị, và
chúng ta ao ước tìm thấy được một giải pháp với giá trị tối ưu (cực tiểu hay cực đại).
Chúng ta gọi giải pháp đó là giải pháp tối ưu cho một bài toán (chưa xác định trước),
đối nghịch với một giải pháp tối ưu (biết rõ ràng), vì vậy có thể có vài giải pháp mà
chúng đạt được giá trị tối ưu.
Sự trình bày của quy hoạch động có thể được chia thành một chuỗi bốn bước sau:
1. Mô tả cấu trúc của giải pháp tối ưu.
2. Định nghĩa giá trị của một giải pháp tối ưu theo cách đệ quy.
3. Tính toán giá trị của một giải pháp tối ưu theo kiểu từ dưới lên.
4. Xây dựng một giải pháp tối ưu từ các dữ liệu đã tính toán.
Các bước từ 1 đến 3 tạo ra nền tảng của một giải pháp quy hoạch động cho một
bài toán. Bước 4 có thể được bỏ qua nếu chỉ một giá trị của một giải pháp tối ưu được
yêu cầu. Khi chúng ta tiến hành bước 4, thỉnh thoảng chúng ta lưu trữ dữ liệu thêm vào
trong suốt quá trình tính toán bước thứ 3, để dễ dàng xây dựng một giải pháp tối ưu.
Các mục trong chương sử dụng phương pháp quy hoạch động để giải quyết vài
bài toán tối ưu. Mục 15.1 khảo sát một bài toán trong việc lập trình cho 2 dây chuyền
sản xuất ô-tô, nơi mà sau mỗi trạm, việc xây dựng dưới ô-tô có thể ở lại trên cùng một
dây chuyền hoặc vận chuyển sang dây chuyền khác. Mục 15.2 yêu cầu cách nào chúng
ta có thể nhân một chuỗi các ma trận sao cho tổng số các phép nhân vô hướng ít nhất
được thực hiện. Cho trước các ví dụ này của quy hoạch động, mục 15.3 thảo luận đến
2 đặc tính cốt yếu mà một bài toán phải có để quy hoạch động là một giải pháp kỹ
thuật có thể thực hiện được. Mục 15.4 sau đó trình bày cách để tìm xâu con chung dài
nhất của 2 xâu. Cuối cùng, mục 15.5 sử dụng quy hoạch động để xây dựng các cây nhị
phân tìm kiếm mà chúng là tối ưu, cho một sự phân bố được biết trước của các khóa
để được tìm kiếm.
15.1. Lập trình cho dây chuyền lắp ráp.
Ví dụ quy hoạch động đầu tiên của chúng ta là giải quyết bài toán sản xuất. Tập
đoàn Motors Colonel sản xuất ô-tô trong một nhà máy mà nó có 2 dây chuyền lắp ráp,
Trang
1
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
được trình bày trong hình 15.1. Một khung gầm ô-tô đưa vào mỗi dây chuyền lắp ráp,
có các bộ phận được thêm vào nó tại một số lượng các trạm, và một chiếc ô-tô được
hoàn tất đưa ra tại cuối dây chuyền. Mỗi dây chuyền lắp ráp có n trạm, được đánh số j
= 1, 2, , n. Chúng ta biểu thị trạm thứ j trên dây chuyền i (với i bằng 1 hoặc 2) bằng
S
i,j
. Trạm thứ j trên dây chuyền 1 (S
1,j
) thực hiện chức năng tương tự như trạm thứ j
trên dây chuyền 2 (S
2,j
). Các trạm được lập nên tại các thời điểm khác nhau và với các
kỹ thuật khác nhau, tuy nhiên, quá nhiều thời gian được yêu cầu tại mỗi biến trạm,
thậm chí giữa các trạm tại vị trí tương tự trên 2 dây chuyền khác nhau. Chúng ta biểu
thị thời gian lắp ráp được yêu cầu tại trạm S
i,j
bằng a
i,j
. Như hình 15.1 hiển thị, một
khung gầm đưa vào trạm 1 của một trong hai dây chuyền lắp ráp, và nó tiến hành từ
mỗi trạm cho tới trạm tiếp theo. Ta cũng có một thời gian đưa vào là e
i
cho mỗi khung
gầm để đưa vào dây chuyền lắp ráp i và thời gian đưa ra là x
i
cho một chiếc ô-tô hoàn
tất để đưa ra dây chuyền lắp ráp i.
Hình 15.1
Hình 15.1: Bài toán sản xuất tìm cách nhanh nhất thông qua một nhà máy. Có 2
dây chuyền lắp ráp, mỗi dây chuyền có n trạm; trạm thứ j của dây chuyền i được biểu
thị là S
i,j
và thời gian lắp ráp tại mỗi trạm là a
i,j
. Một khung gầm xe ô-tô đưa vào nhà
máy, và đi vào dây chuyền i (với i bằng 1 hoặc 2) mất e
i
thời gian. Sau khi đi qua trạm
thứ j của một dây chuyền, khung gầm xe đi tới trạm thứ j+1 trên dây chuyền kia.
Không có chi phí vận chuyển nếu nó nằm trên cùng một dây chuyền, nhưng mất thời
gian t
i,j
để vận chuyển tới một dây chuyền khác sau trạm S
i,j
. Sau khi đi ra trạm thứ n
trên một dây chuyền, nó tốn mất x
i
thời gian cho một ô-tô được hoàn tất để đưa ra nhà
máy. Bài toán này là xác định các trạm nào được chọn trên dây chuyền 1 và các trạm
nào được chọn trên dây chuyền 2 để cực tiểu hóa tổng thời gian đi qua nhà máy cho
một chiếc ô-tô.
Thông thường, một khung gầm ô-tô đưa vào một dây chuyền lắp ráp, nó đi qua
chỉ dây chuyền đó mà thôi. Thời gian để đi từ một trạm đến trạm tiếp theo trong cùng
một dây chuyền lắp ráp là không đáng kể. Thỉnh thoảng một đơn đặt dồn lên đột ngột
đặc biệt đưa đến, và khách hàng muốn xe ô-tô được sản xuất càng nhanh trong mức có
thể. Với các đơn đặt dàng dồn lên đột ngột, khung gầm xe vẫn đi qua n trạm theo thứ
thự, nhưng người quản lý nhà máy có thể chuyển ô-tô hoàn tất bộ phận từ một dây
chuyền lắp ráp này sang một dây chuyền lắp ráp khác sau bất kỳ trạm nào. Thời gian
để vận chuyển một khung gầm xe ra khỏi từ dây chuyền lắp ráp i sau khi đã đi qua
trạm S
i,j
là t
i,j
, với i = 1, 2 và j = 1, 2, , n-1 (vì sau trạm thứ n, việc lắp ráp đã hoàn
tất). Bài toán này là xác định các trạm nào được chọn từ dây chuyền 1 và trạm nào
được chọn trên dây chuyền 2 để cực tiểu hóa tổng thời gian đi qua nhà máy cho một
Trang
2
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
chiếc ô-tô. Trong ví dụ ở hình 15.2(a), tổng thời gian nhanh nhất từ việc chọn các trạm
1, 3 và 6 từ dây chuyền 1 và các trạm 2, 4 và 5 từ dây chuyền 2.
Hình 15.2
Hình 15.2: (a) Một ví dụ cho bài toán dây chuyền lắp ráp với các chi phí e
i
, a
i,j
, t
i,j
và x
i
được biểu thị. Đường đi in bóng đậm biểu thị cách nhanh nhất đi qua nhà máy.
(b) Giá trị của f
i
[j], f
*
, l
i
[j], và l
*
với ví dụ trong phần (a).
Rõ ràng rằng, cách “brute force” (sức mạnh tàn bạo) của việc cực tiểu hóa thời
gian đi qua nhà máy là không thể làm được khi có quá nhiều trạm. Nếu chúng ta có
trước một danh sách các trạm mà chúng được dùng trong dây chuyền 1 và các trạm
được dùng trong dây chuyền 2, thì điều đó thật dễ dàng để tính toán với Θ(n) thời gian
phải mất bao lâu để nó đưa một khung gầm xe đi qua nhà máy. Thậy không may, có 2
n
cách có thể để chọn các trạm, mà chúng ta có thể xem xét bằng cách nhìn tập các trạm
được sử dụng trong dây chuyền 1 như là một tập con của {1, 2, , n} và lưu ý rằng có
2
n
các tập con như vậy. Theo cách đó, việc xác định cách nhanh nhất đi qua nhà máy
bằng cách liệt kê tất cả các cách có thể và tính toán phải mất bao lâu để mỗi trường
hợp sẽ đòi hỏi Ω(2
n
) thời gian, điều này là không thể làm được khi n là lớn.
Bước 1: Cấu trúc của cách nhanh nhất đi qua nhà máy.
Bước đầu tiên của mô hình quy hoạch động là mô tả cấu trúc của một giải pháp
tối ưu. Với bái toán lập trình cho dây chuyền lắp ráp, chúng ta có thể biểu diễn bước
này theo cách sau. Chúng ta hãy tính cách nhanh nhất có thể cho một khung gầm xe để
đưa vào từ điểm bắt đầu thông qua trạm S
1,j
. Nếu j = 1, chỉ có một cách mà khung gầm
xe có thể được đưa vào, và vì vậy thật dễ dàng để xác định phải mất bao lâu để nó đi
qua trạm S
1,j
. Tuy nhiên, với j = 2, 3, , n, thì có 2 lựa chọn: khung gầm xe có thể
được đưa đến từ trạm S
1,j-1
và sau đó đi trực tiếp đến S
1,j
, thời gian cho việc đi từ trạm
j-1 đến trạm j trên cùng một dây chuyền là không đáng kể. Một sự lựa chọn khác,
khung gầm xe có thể được đưa đến từ trạm S
2,j-1
và sau đó được vận chuyển đế trạm
Trang
3
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
S
1,j
, thời gian vận chuyển là t
2,j-1
. Chúng ta sẽ tính toán 2 cách có thể này một cách
riêng biệt, mặc dù chúng ta sẽ thấy rằng chúng có rất nhiều điểm chung.
Đầu tiên, chúng ta giả sử rằng cách nhanh nhất qua trạm S
1,j
là thông qua trạm
S
1,j-1
. Điều mấu chốt của sự quan sát là khung gầm xe phải thu được cách nhanh nhất từ
điểm bắt đầu thông qua trạm S
1,j-1
. Tại sao như vậy? Nếu có cách nhanh hơn để đi qua
trạm S
1,j-1
, chúng ta có thể thay thế cách nhanh hơn này để sinh ra một cách nhanh hơn
đi qua trạm S
1,j
: mâu thuẫn.
Tương tự, bây giờ chúng ta giả sử rằng cách nhanh nhất đi qua trạm S
1,j
là qua
trạm S
2,j-1
. Bây giờ chúng ta thấy rằng khung gầm xe phải thu được cách nhanh nhất từ
điểm bắt đầu qua trạm S
2,j-1
. Lý do tương tự: nếu có cách nhanh hơn để đi qua trạm S
2,j-
1
, chúng ta có thể thay thế cách nhanh hơn này để sinh ra cách nhanh hơn đi qua trạm
S
1,j
, điều này cũng sẽ là mâu thuẫn.
Tóm lại, chúng ta có thể nói rằng với việc lập trình cho dây chuyền lắp ráp, một
giải pháp tối ưu cho bài toán (tìm cách nhanh nhất đi qua trạm S
i,j
) bao gồm một giải
pháp tối ưu cho các bài toán con (tìm cách nhanh nhất đi qua hoặc là trạm S
1,j-1
hoặc là
trạm S
2,j-1
) trong phạm vi của nó. Chúng ta quy đặc tính này là cấu trúc con tối ưu, và
nó là một trong các tiêu chuẩn của quy hoạch động có thể dùng được, mà chúng ta sẽ
xem xét ở mục 15.3.
Chúng ta sử dụng cấu trúc con tối ưu để chỉ ra rằng chúng ta có thể xây dựng một
giải pháp tối ưu cho một bài toán từ các giải pháp tối ưu cho các bài toán con. Với việc
lập trình cho dây chuyền lắp ráp, chúng ta lý giải theo cách sau. Nếu chúng ta thấy
cách nhanh nhất đi qua trạm S
1,j
, thì nó phải đi qua trạm j-1 trên dây chuyền 1 hoặc là
trên dây chuyền 2. Theo cách đó, cách nhanh nhất đi qua trạm S
1,j
là:
•Hoặc là cách nhanh nhất đi qua trạm S
1,j-1
và sau đó đi trực tiếp qua trạm
S
1,j
.
•Hoặc là cách nhanh nhất đi qua trạm S
2,j-1
, vận chuyển từ dây chuyền 2
sang dây chuyền 1, và sau đó đi qua trạm S
1,j
.
Sử dụng lập luận đối xứng, cách nhanh nhất đi qua trạm S
2,j
là:
•Hoặc là cách nhanh nhất đi qua trạm S
2,j-1
và sau đó đi trực tiếp qua trạm
S
2,j
.
•Hoặc là cách nhanh nhất đi qua trạm S
1,j-1
, vận chuyển từ dây chuyền một
sang dây chuyền 2, và sau đó đi qua trạm S
2,j
.
Để giải quyết bài toán của việc tìm cách nhanh nhất qua trạm j của 1 trong 2 dây
chuyền, chúng ta giải quyết các bài toán con của việc tìm các cách nhanh nhất đi qua
trạm j-1 on cả 2 dây chuyền.
Theo cách đó, chúng ta có thể xây dựng một giải pháp tối ưu cho ví dụ bài toán
lập trình cho dây chuyền lắp ráp bằng cách xây dựng các giải pháp tối ưu cho các bài
toán con.
Bước 2: Giải pháp đệ quy.
Bước thứ 2 của mô hình quy hoạch động là xác định giá trị của giải pháp tối ưu
đệ với các số hạng của các giải pháp tối ưu cho các bài toán con. Với bài toán lập trình
cho dây chuyền lắp ráp, chúng ta chọn các bài toán con của chúng ta, các bài toán của
việc tìm cách nhanh nhất đi qua trạm j trên cả 2 dây chuyền, với j = 1, 2, , n. f
i
[j] để
Trang
4
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
biểu thị thời gian nhanh nhất có thể để đưa khung gầm xe từ điểm bắt đầu đi qua trạm
S
i,j
.
Mục đích cuối cùng của chúng ta là xác định thời gian nhanh nhất để đưa một
khung gầm xe vào tất cả các cách đi qua nhà máy, mà chúng ta biểu thị bằng f
*
. Khung
gầm xe phải đưa vào tất cả các cách qua trạm n hoặc là trên dây chuyền 1 hoặc là trên
dây chuyền 2 và sau đó đưa ra khỏi nhà máy. Vì cách nhanh hơn của các cách đó là
cách nhanh nhất đi qua toàn bộ nhà máy, chúng ta có:
(15.1) f
*
= min(f
1
[n] + x
1
, f
2
[n] + x
2
)
Điều này cũng dễ dàng để lý giải về f
1
[1] và f
2
[1]. Để đưa qua trạm 1 trên một
trong 2 dây chuyền, một khung gầm xe phải đi trực tiếp đến trạm đó. Theo cách đó,
(15.2) f
1
[1] = e
1
+ a
1,1
(15.3) f
1
[1] = e
2
+ a
2,1
Bây giờ chúng ta hãy tính xem bằng cách nào để tính f
i
[j], với j = 2, 3, , n (và i
= 1, 2). Tiêu điểm là f
1
[j], chúng ta nhớ lại rằng cách nhanh nhất qua trạm S
1,j
là cách
nhanh nhất qua trạm S
1,j-1
và sau đó trực tiếp qua trạm S
1,j
, hoặc là cách nhanh nhất qua
trạm S
2,j-1
, vận chuyển từ dây chuyền 2 sang dây chuyền 1, và sau đó qua trạm S
1,j
.
Trong trường hợp đầu tiên, chúng ta có f
1
[j] = f
1
[j-1] + a
1,j
, và trong trường hợp sau là
f
1
[j] = f
2
[j-1] + t
2,j-1
+ a
1,j
. Theo cách đó,
(15.4) f
1
[j] = min(f
1
[j-1] + a
1,j
, f
2
[j-1] + t
2,j-1
+ a
1,j
)
Với j = 2, 3, , n. Đối xứng, chúng ta có
(15.5) f
2
[j] = min(f
2
[j-1] + a
2,j
, f
1
[j-1] + t
1,j-1
+ a
2,j
)
Với j = 2, 3, , n. Phối hợp 2 phương trình (15.2)-(15.5), chúng ta thu được các
phương trình đệ quy:
Hình 15.2(b) cho thấy các giá trị f
i
[j] cho ví dụ của phần (a), được tính toán bằng
các phương trình (15.6) và (15.7), dọc theo với các giá trị của f
*
.
Các giá trị f
i
[j] mang lại các giá trị của các giải pháp tối ưu cho các bài toán con.
Để trợ giúp chúng ta lưu giữ dấu vết của cách xây dựng một giải pháp tối ưu, chúng ta
định nghĩa l
i
[j] là số dây chuyền, 1 hoặc 2, mà các trạm của chúng được dùng trong
cách nhanh nhất đi qua trạm S
i,j
. Ở đây, i = 1, 2 và j = 2, 3, , n. (Chúng ta ngăn ngừa
việc định nghĩa l
i
[1] bởi vì không có trạm nào trước trạm 1 trên một trong 2 dây
chuyền). Chúng ta cũng định nghĩa l
*
là một dây chuyền mà trạm n của chúng được
dùng trong cách nhanh nhất đi qua toàn bộ nhà máy. Các giá trị l
i
[j] trợ giúp chúng ta
truy lại được cách nhanh nhất. Việc sử dụng các giá trị của l
*
và l
i
[j] được trình bày
trong hình 15.2(b), chúng ta sẽ truy lại được cách nhanh nhất đi qua nhà máy trong
phần (a) theo cách này. Bắt đầu với l
*
= 1, chúng ta sử dụng trạm S
1,6
. Bây giờ chúng ta
thấy l
1
[6], nó bằng 2, và vì vậy chúng ta sử dụng trạm S
2,5
. Tiếp tục, chúng ta thấy l
2
[5]
= 2 (sử dụng trạm S
2,4
), l
2
[4] = 1 (trạm S
1,3
), l
1
[3] = 2 (trạm S
2,2
), và l
2
[2] = 1 (trạm S
1,1
).
Bước 3: Tính toán các thời gian nhanh nhất.
Trang
5
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
Tại điểm này, nó sẽ là một nội dung đơn giản để viết một thuật toán đệ quy được
dựa vào phương trình (15.1) và các phép truy toán (15.6) và (15.7) để tính cách nhanh
nhất đi qua nhà máy. Có một bài toán với một thuật toán đệ quy: thời gian chạy của nó
là một hàm mũ với n. Để thấy tại sao, hãy xem r
i
(j) là số lượng của các tham chiếu
được tạo bởi f
i
[j] trong một thuật toán đệ quy, từ phương trình (15.1) chúng ta có
(15.8) r
1
(n) = r
2
(n) = 1
Từ các phép truy toán (15.6) và (15.7) chúng ta có
(15.9) r
1
(j) = r
2
(j) = r
1
(j-1) + r
2
(j-1)
Với j = 1, 2, , n-1. Như bài tập 15.1-2 yêu cầu bạn chỉ ra, r
i
(j) = 2
n-j
. Theo cách
đó, chỉ một mình f
1
[1] được tham chiếu 2
n-1
thời gian! Như bài tập 15.1-3 yêu cầu bạn
chỉ ra tổng số lượng các tham chiếu đến tất cả các giá trị f
i
[j] là Θ(2
n
).
Chúng ta có thể làm tốt hơn nếu chúng ta tính các giá trị f
i
[j] theo một thứ tự
khác biệt từ cách đệ quy. Để ý rằng với j ≥ 2, mỗi giá trị của f
i
[j] chỉ phụ thuộc vào các
giá trị của f
1
[j-1] và f
2
[j-1]. Bằng cách tính các giá trị của f
i
[j] theo thứ tự tăng dần các
số j trạm – từ trái qua phải trong hình 15.2(b) – chúng ta có thể tính được cách nhanh
nhất đi qua nhà máy, và thời gian mà nó tiêu tốn, trong Θ(n) thời gian. Thủ tục
FASTEST-WAY lấy đầu vào như là các giá trị a
i,j
, t
i,j
, e
i
, x
i
, cũng như là n, số lượng
các trạm của mỗi dây chuyền.
FASTEST-WAY (a, t, e, x, n)
1 f
1
[1] e
1
+ a
1,1
2 f
2
[2] e
2
+ a
2,1
3 for j 2 to n do
4 if f
1
[j-1] + a
1,j
≤ f
2
[j-1] + t
2,j-1
+ a
1,j
5 then f
1
[j] f
1
[j-1] + a
1,j
6 l
1
[j] 1
7 else f
1
[j] f
2
[j-1] + t
2,j-1
+ a
1,j
8 l
1
[j] 2
9 if f
2
[j-1] + a
1,j
≤ f
1
[j-1] + t
2,j-1
+ a
1,j
10 then f
2
[j] f
2
[j-1] + a
1,j
11 l
2
[j] 2
12 else f
2
[j] f
1
[j-1] + t
2,j-1
+ a
1,j
13 l
2
[j] 1
14 if f
1
[n] + x
1
≤ f
2
[n] + x
2
15 then f
*
= f
1
[n] + x
1
16 l
*
= 1
17 else f
*
= f
2
[n] + x
2
16 l
*
= 2
Thủ tục FASTEST-WAY làm việc theo cách sau. Các dây chuyền 1-2 tính f
1
[1]
và f
2
[1] sử dụng các phương trình (15.2) và (15.3). Sau đó vòng for của các hàng 3 tới
13 tính f
i
[j] và l
i
[j] với i = 1, 2 và j = 2, 3, , n. Các dòng 4 đến 8 tính f
1
[j] và l
1
[j] sử
dụng phương trình (15.4), và các dòng 9 đến 13 tính f
2
[j] và l
2
[j] sử dụng phương trình
(15.5). Cuối cùng, các hàng 14 đến 18 tính f
*
và l
*
sử dụng phương trình (15.1). Bởi vì
các hàng 1 đến 2 và 14 đến 18 thu được hằng số thời gian và mỗi cái của n-1 sự tính
Trang
6
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
lặp của vòng for ở hàng 3 đến 13 thu được hằng số thời gian, toàn bộ thủ tục tốn mất
Θ(n) thời gian.
Một cách để thấy quá trình tính toán các giá trị của f
i
[j] và l
i
[j] là chúng ta đang
điền vào các mục nhập bảng. Tham chiếu hình 15.2(b), chúng ta điền vào bảng bao
gồm các giá trị f
i
[j] và l
i
[j] từ trái qua phải (và từ trên xuống dưới với mỗi cột). Để điền
vào một mục nhật f
i
[j], chúng ta cần các giá trị f
1
[j-1] và f
2
[j-1], và biết rằng chúng ta
đã tính toán và lưu trữ chúng, chúng ta xác định các giá trị này một cách đơn giản
bằng việc tìm chúng ở trong bảng.
Bước 4: Việc xây dựng cách nhanh nhất đi qua nhà máy.
Đã tính toán được các giá trị f
i
[j], f
*
, l
i
[j], và l
*
, chúng ta cần xây dựng chuỗi các
trạm được sử dụng trong cách nhanh nhất đi qua nhà máy. Chúng ta đã bàn luận ở trên
cách nào để làm được như ví dụ ở hình 15.2.
Theo thủ tục in ra các trạm được sử dụng, theo thứ tự giảm dần số của trạm. Bài
tập 15.1-1 yêu cầu bạn chỉnh sửa nó để in ra các trạm theo thứ tự tăng dần số của trạm.
PRINT-STATIONS (l, n)
1 i l
*
2 print “line” i “, station ” n
3 for j n downto 2
4 do i l
i
[j]
5 print “line ” i “, station ” j-1
Trong ví dụ của hình 15.2, PRINT-STATIONS sẽ cho ra kết quả là
Line 1, station 6
Line 2, station 5
Line 2, station 4
Line 1, station 3
Line 2, station 2
Line 1, station 1
Bài tập:
15.1-1: Hãy trình bày cách chỉnh sửa thủ tục PRINT-STATIONS để in ra các
trạm theo thứ tự tăng dần số của trạm. (Gợi ý: sử đụng đệ quy)
15.1-2: Hãy sử dụng các phương trình (15.8) và (15.9) và phương pháp thay thế
để chỉ ra rằng r
i
(j), số lượng các tham chiếu được tạo ra từ f
i
[j] trong thuật toán đệ quy,
bằng 2
n-j
.
15.1-3: Sử dụng kết quả của bài tập 15.1-2, hãy chỉ ra rằng tổng số lượng các
tham chiếu cho tất cả các giá trị f
i
[j], hoặc
∑
=
2
1i
∑
=
n
j 1
r
i
(j) , bằng chính xác 2
n+1
– 2.
15.1-4: Kết hợp với, các giá trị f
i
[j] và l
i
[j] trong bảng chứa bao gồm một tổng
của 4n–2 các mục nhập. Hãy chỉ ra cách làm giảm các yêu cầu khoảng cách tới một
tổng của 2n+2 các mục nhập, trong khi vẫn tính được f
*
và vẫn có thể in tất cả các
trạm trong cách nhanh nhất đi qua nhà máy.
15.1-5: Giáo sư Canty phỏng đoán rằng phải tồn tại một vài giá trị e
i
, a
i,j
và t
i,j
mà với chúng FASTEST-WAY sinh ra các giá trị l
i
[j] như là l
1
[j] = 2 và l
2
[j] = 1 với
Trang
7
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
vài số của trạm j. Giả sử rằng tất cả các chi phí vận chuyển t
i,j
là không âm, hãy chỉ ra
rằng giáo sư sai.
15.2. Phép nhân tổ hợp ma trận:
Ví dụ tiếp theo của quy hoạch động là một thuật toán giải quyết bài toán nhân
tổ hợp nhiều ma trận.
Cho một dãy các ma trận A
1
, A
2
, …, A
n
, ta cần tính A
1
.A
2
…A
n
. (1)
Ta có thể định lượng biểu thức (1) sử dụng thuật toán chuẩn để nhân lần lượt từng cặp
ma trận được đặt trong ngoặc đơn lại với nhau. Một kết quả của phép nhân các ma trận
là một cách đặt các dấu ngoặc đơn trong phép nhân, là ngoặc đơn cho một ma trận với
một phép nhân hoặc một cặp hai ma trận nhân với nhau. Nhân nhiều ma trận là phép
kết hợp, tất cả các cách kết hợp đều cho một ma trận kết quả.
Ví dụ tổ hợp các ma trận đã cho là A
1
, A
2
, A
3
, A
4
, thì kết quả có thể thu được từ
cách đặt dấu ngoặc trong phép nhân, có 5 cách như sau:
(A
1
(A
2
(A
3
A
4
))) ,
(A
1
((A
2
A
3
) A
4
)) ,
((A
1
A
2
) (A
3
A
4
)) ,
((A
1
(A
2
A
3
)) A
4
) ,
(((A
1
A
2
) A
3
) A
4
).
Mỗi cách mà chúng ta đặt các ma trận trong dấu ngoặc đơn có thể ảnh hưởng
đến kết quả tính toán (số phép tính). Đầu tiên để ý đến cái giá thu được khi nhân hai
ma trận. Thuật toán chuẩn được cho bởi đoạn mã giả sau, trong đó rows[A] là số hàng
của ma trận A, columns[A] là số cột của ma trận A.
MATRIX-MULTIPLY(A, B)
1 if columns[A] ≠ rows[B]
2 then error "chiều không thích hợp"
3 else for i 1 to rows[A]
4 do for j 1 to columns[B]
5 do C[i, j] 0
6 for k 1 to columns[A]
7 do C[i, j] C[i, j] + A[i, k] · B[k, j]
8 return C
Ta có thể nhân hai ma trận A và B nếu số cột của ma trận A bằng số hàng của
ma trận B. Nếu ma trận A có kích thước là p.q, ma trận B có kích thước là q.r thì ma
trận kết quả C có kích thước là p.r. Thời gian để tính toán ma trận C được thể hiện
bằng số các phép nhân vô hướng, là pqr. Trong thuật toán trên, được thể hiện ở dòng
7.
Để biểu thị giá của phép nhân ma trận với cách đặt các cách đặt ngoặc đơn khác
nhau, ta xét bài toán với 3 ma trận A
1
, A
2
, A
3
. Giả sử rằng, các ma trận có kích thước
tương ứng là: 10 × 100, 100 × 5, và 5 × 50.
- Nếu thực hiện ((A
1
A
2
) A
3
), ta cần 10.100.5 = 5000 phép nhân để nhân
A
1
với A
2
, 10.5.50 = 2500 phép nhân để nhân ma trận kết quả với A
3
,
tổng cộng là 7500 phép nhân, tức là giá của phép nhân này là 7500.
Trang
8
Tiểu luận PT&TKTT: Thuật tốn Quy hoạch động_________________________________Nhóm 3
- Nếu ta thực hiện (A
1
(A
2
A
3
)), ta cần thực hiện 100·5·50 = 25000 phép
nhân để nhân A
2
với A
3
, thêm vào đó là 10·100·50 = 50000 phép nhân
để nhân A
1
với ma trận tích trên, và có tổng cộng là 75000 phép nhân,
tức là giá của phép nhân này là 75000.
Đối chiếu hai cách trên, ta thấy cách thứ nhất nhanh hơn 10 lần so với cách thứ
2.
Bài tốn nhân tổ hợp ma trận có thể được phát biểu như sau:
Cho một tổ hợp các ma trận A
1
, A
2
, …., A
n
. Ma trận A
i
có chiều là p
i-1
×p
i
, hãy
xác định cách thực hiện phép nhân A
1
.A
2
…A
n
sao cho số phép nhân là ít nhất.
Chú ý rằng trong bài tốn nhân tổ hợp ma trận, chúng ta thực sự khơng đi
nhân ma trận, mà vấn đề là ta xác định trật tự của việc nhân ma trận sao cho chi phí
thu được là nhỏ nhất.
Đếm số cách đặt dấu ngoặc đơn:
Trước khi giải quyết bài tốn nhân tổ hợp nhiều ma trận bằng quy hoạch động,
chúng ta kiểm tra xem có bao nhiêu cách đặt ngoặc đơn có thể cần để thực hiện phép
tính. Biểu diễn số cách đặt ngoặc đơn để nhân n ma trận là P(n). Ta có:
−
=
∑
=
n
k
kPkP
nP
1
)1().(
1
)(
Các bước giải quyết bài tốn nhân tổ hợp nhiều ma trận:
Bước 1: Cấu trúc của một tổ hợp dấu ngoặc tối ưu:
Bước 1 của phương pháp dynamic programming là:
• Xác đònh tính chất cấu trúc con tối ưu.
• Dựa vào đó xây dựng lời giải tối ưu cho bài toán từ các lời giải tối ưu
cho các bài toán con.
Ở đây:
Gọi A
i j
là ma trận có được từ tích A
i
A
i+1
×××
A
j.
Nhận xét: Một đóng ngoặc tối ưu bất kỳ của tích A
i
A
i+1
×××A
j
đều có thể tách nó
giữa A
k
và A
k+1
, với k nào đó thõa i ≤ k < j :
(A
i
A
i+1
××× A
k
)(A
k+1
××× A
j
)
Nghóa là đầu tiên ta tính tích các ma trận A
i k
và A
k+1 j
, sau đó ta nhân
chúng với nhau để có tích cuối cùng A
i j
. Do đó phí tổn để tính tích từ đóng
ngoặc tối ưu là phí tổn để tính A
i k
, cộng phí tổn để tính A
k+1 j
, cộng phí
tổn để nhân chúng với nhau.
° Cấu trúc con tối ưu
Trang
9
Nếu n = 1,
Nếu n ≥ 2.
Tiểu luận PT&TKTT: Thuật tốn Quy hoạch động_________________________________Nhóm 3
— Đóng ngoặc của chuỗi con “tiền tố” A
i
A
i+1
××× A
k
có được từ đóng
ngoặc tối ưu của A
i
A
i+1
××× A
j
phải là một đóng ngoặc tối ưu của A
i
A
i+1
××× A
k
. (Chứng minh bằng phản chứng).
— Tương tự, đóng ngoặc của chuỗi con còn lại A
k+1
A
k+2
××× A
j
có được
từ đóng ngoặc tối ưu của A
i
A
i+1
××× A
j
phải là một đóng ngoặc tối ưu
của A
k+1
A
k+2
××× A
j
.
Để cho gọn, sẽ nói “phí tổn của một đóng ngoặc” thay vì nói “phí tổn để tính
tích từ một đóng ngoặc”.
° Xây dựng lời giải tối ưu
— Chia bài toán thành hai bài toán con.
— Tìm lời giải tối ưu cho mỗi bài toán con.
— Kết hợp các lời giải tìm được ở trên.
Cần tìm vò trí thích hợp (trò của k) để tách chuỗi ma trận A
i
A
i+1
×××
A
j
!
Bước 2: Giải đệ quy:
° Bước 2 của phương pháp quy hoạch động là:
— Đònh nghóa đệ quy phí tổn của một lời giải tối ưu tùy theo các lời giải
tối ưu của các bài toán con.
° Bài toán con ở đây là : Xác đònh phí tổn tối thiểu cho một đóng ngoặc của
chuỗi ma trận A
i
A
i+
1
××× A
j
với 1 ≤ i ≤ j ≤ n.
° Đònh nghóa m[i, j] là số phép nhân vô hướng tối thiểu để tính ma trận A
i j
.
Phân biệt hai trường hợp:
— Nếu i = j thì A
i
A
i+
1
×××A
j
= A
i
. Vậy, với i = 1, , n,
m[i, i] = 0.
— Nếu i < j thì từ bước 1 ta có:
m[i, j] = m[i, k] + m[k + 1, j] + p
i
−
1
p
k
p
j
Vậy, ta có:
Để ghi lại cách xây dựng lời giải tối ưu ta đònh nghóa s[i, j] là trò của k xác
đònh nơi tách chuỗi A
i
A
i
+1
××× A
j
để có một đóng ngoặc tối ưu. Nghóa là s[i, j] là
một trò k mà
Trang
10
+++
=
−
<≤
}],1[],[{min
0
],[
1 jki
jki
pppjkmkim
jim
Nếu i=j,
Nếu i<j.
Tiểu luận PT&TKTT: Thuật tốn Quy hoạch động_________________________________Nhóm 3
m[i, j] = m[i, k] + m[k + 1, j] + p
i
−
1
p
k
p
j
.
Bước 3: Tính các chi phí tối ưu
° Bước 3 của phương pháp dynamic programming là tính chi phí tối ưu bằng
một phương pháp từ dưới lên (bottom-up) và dùng bảng.
° Nhận xét :
— Có thể viết được ngay một giải thuật đệ quy (dựa trên hàm đệ quy đã
tìm được) để tính phí tổn tối ưu m[1, n] cho tính tích A
1
A
2
××× A
n
.
Nhưng sau này chúng ta sẽ thấy là giải thuật này chạy trong thời gian
lũy thừa.
Ma trận A
i
có chiều là p
i
−
1
× p
i
, với i = 1, 2, , n .
Input: là một chuỗi p = < p
0
, p
1
, , p
n
>
Output: Giải thuật trả về hai bảng m[1 n, 1 n] và s[1 n, 1 n].
MATRIX-CHAIN-ORDER(p)
1 n ¬ length[p] − 1
2 for i ¬ 1 to n
3 do m[i, i] ¬ 0
4 for l ¬ 2 to n { duyệt l, độ dài của A
i j
}
5 do for i ¬ 1 to n − l + 1 {duyệt vò trí của A
i j
}
6 do j ¬ i + l − 1 {tính j}
7 m[i, j] ¬ ∞
8 for k ¬ i to j − 1 {duyệt k, vò trí tách A
i j
}
9 do q ¬ m[i, k] + m[k + 1, j] + p
i
−1
p
k
p
j
10 if q < m[i, j]
11 then m[i, j] ¬ q
12 s[i, j] ¬ k
13 return m and s
° Thời gian chạy của MATRIX-CHAIN-ORDER là O(n
3
):
— Giải thuật có 3 vòng lặp lồng vào nhau, mỗi chỉ số của vòng lặp (l, i,
và k) có thể có đến n trò.
° Giải thuật cần bộ nhớ Θ(n
2
) cho các bảng m và s.
Trang
11
Tiểu luận PT&TKTT: Thuật tốn Quy hoạch động_________________________________Nhóm 3
Chạy MATRIX-CHAIN-ORDER với đầu vào:
Input:
Output: bảng m và s như hình dưới:
° Quay các bảng m và s một góc 45 độ ngược chiều kim đồng hồ
° Ví dụ:
m[2,5] = min
= 7125
Trang
12
ma trận chiều
A
1
30 × 35
A
2
35 × 15
A
3
15 × 5
A
4
5 × 10
A
5
10 × 20
A
6
20 × 25
11,8
75
9,37
5
15,1
25
15,7
50
0
7,87
5
7,12
5
4,37
5
10,5
00
0
2,62
5
2,50
0
750
5,37
5
0
1,00
0
0
3,50
0
5,00
0
0 0
m
j i
1
1
6
6
3
3
3
1
1
3
3
3
2
3
3
3
4
5
5
s
j i
1
2
6
5
m[2,2] + m[3,5] + p
1
p
2
p
5
= 0 + 2500 + 35 ⋅ 15 ⋅ 20 = 13000,
m[2,3] + m[4,5] + p
1
p
3
p
5
= 2625 + 1000 + 35 ⋅ 5 ⋅ 20 = 7125,
m[2,4] + m[5,5] + p
1
p
4
p
5
= 4375 + 0 + 35 ⋅ 10 ⋅ 20 = 11375
Tiểu luận PT&TKTT: Thuật tốn Quy hoạch động_________________________________Nhóm 3
Bước 4: Xây dựng một lời giải tối ưu
° Bảng s[1 n, 1 n] trữ một cách đóng ngoặc tối ưu do MATRIX-CHAIN-
ORDER tìm ra.
° Thủ tục sau, MATRIX-CHAIN-MULTIPLY, trả về tích của chuỗi ma trận
A
i j
khi cho A = 〈A
1
, A
2
, A
3
, , A
n
〉, bảng s, và các chỉ số i và j.
MATRIX-CHAIN-MULTIPLY(A, s, i, j)
1 if j > i
2 then X ¬ MATRIX-CHAIN-MULTIPLY(A, s, i, s[i, j])
3 Y ¬ MATRIX-CHAIN-MULTIPLY(A, s, s[i, j] + 1, j)
4 return MATRIX-MULTIPLY(X, Y)
5 else return A
i
Trong bài toán tổng quát, chỉ cần gọi MATRIX-CHAIN-MULTIPLY(A, s, 1,
n) để tính tích của chuỗi ma trận A.
15.3 Các thành phần của quy hoạch động.
Mặc dầu chúng ta đi sâu tìm hiểu với 2 ví dụ của phương pháp quy hoạch động,
nhưng ắt hẳn bạn sẽ suy nghĩ là khi nào sẽ ứng dụng phương pháp này. Từ một góc độ
khoa học, khi nào thì chúng ta nên tìm kiếm một giải pháp quy hoạch động cho một
bài tốn? Trong mục này, chúng ta xem xét 2 vấn đề cốt yếu mà bài tốn tối ưu phải có
để cho chương trình quy hoạch động có thể áp dụng được: tối ưu cấu trúc con và độ
thích hợp của các bài tốn con. Chúng ta cũng phải xem xét một phương pháp biến,
được gọi là memoization
(1)
, chọn sự thuận lợi của thuộc tính tương thích giữa các bài
tốn con.
Cấu trúc con tối ưu.
Bước đầu tiên trong việc giải quyết một bài tốn tối ưu bằng quy hoạch động là
mơ tả cấu trúc của một giải pháp tối ưu. Hãy nhớ lại một bài tốn đưa ra cấu trúc con
tối ưu nếu một giải pháp tối ưu cho một bài tốn bao gồm các giải pháp tối ưu cho các
bài tốn con trong phạm vi của nó. Cứ mỗi khi một bài tốn đưa ra cấu trúc con tối ưu,
thì nó là một tư tưởng (manh mối) tốt mà quy hoạch động có thể áp dụng. (Nó cũng có
nghĩa rằng chiến lược tham lam được áp dụng. Xem Chương 16). Trong quy hoạch
động, chúng ta xây dựng một giải pháp tối ưu cho một bài tốn từ các giải pháp tối ưu
cho các bài tốn con. Do đó, chúng ta phải thật cẩn thận để chắc chắn rằng dãy các bài
tốn con mà chúng ta tính tốn đến chúng được sử dụng trong một giải pháp tối ưu.
Chúng ta đã khám phá cấu trúc con tối ưu trong cả 2 mặt của các bài tốn mà
chúng ta xem xét trong chương này ở một mức độ nhất định mà thơi. Trong mục 15.1,
chúng ta đã xem xét cách nhanh nhất qua trạm thứ j của 2 dây chuyền bao gồm cách
nhanh nhất thơng qua trạm thứ j-1 trên 1 dây chuyền trong phạm vi của nó. Trong mục
15.2, chúng ta đã xem xét việc đặt dấu ngoặc đơn tối ưu của dãy A
i
A
i+1
A
j
mà nó tách
sản phẩm giữa A
k
và A
k+1
bao gồm các giải pháp tối ưu cho các bài tốn của việc đặt
dấu ngoặc đơn 2 dãy con A
i
A
i+1
A
k
và A
k
A
k+1
A
j
.
Trang
13
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
Bạn sẽ tìm chính bản thân bạn theo một mẫu chung trong việc khám phá cấu
trúc con tối ưu:
1. Bạn trình bày giải pháp cho một bài toán bao gồm việc lựa chọn,
giống như là chọn một trạm cho trước trên dây chuyền lắp ráp hoặc là chọn một
chỉ mục (hoặc vị trí) mà tại đó ta cắt chuỗi ma trận. Việc lựa chọn này tạo ra
một hoặc nhiều bài toán con để được giải quyết.
2. Bạn giả định rằng với một bài toán đã cho, bạn được cho một lựa
chọn mà nó dẫn đến một giải pháp tối ưu. Bạn không cần bận tâm tới bằng cách
nào xác định lựa chọn đó. Bạn chỉ giả bộ rằng nó đã được đưa cho bạn.
3. Với lựa chọn đã cho đó, bạn xác định các bài toán con sinh ra sau
đó và cách để mô tả tốt nhất kết quả khoảng cách của các bài toán con.
4. Bạn trình bày các giải pháp cho các bài toán con được mà chúng
sử dụng trong giải pháp tối ưu cho bài toán mà bản thân chúng là phải tối ưu,
bằng cách sử dụng một kỹ thuật “cắt và dán”. Rồi bạn làm tiếp tục bằng cách
giả định rằng mỗi giải pháp của một bài toán con không phải là tối ưu và sau đó
lại xuất phát một mâu thuẫn. Nói tóm lại, bằng cách “cắt ra” giải pháp bài toán
con không tối ưu và “dán vào” giải pháp bài toán con tối ưu, bạn trình bày rằng
bạn có thể có được một giải pháp tốt hơn cho một bài toán gốc, với việc phủ
định giả định của bạn như vậy bạn đã có một giải pháp tối ưu. Nếu có nhiều
hơn một bài toán con, thì chúng là điển hình tương tự nhau mà luận cứ cắt và
dán cho một bài toán con có thể được chỉnh sửa cho các bài toán con khác với
sự nỗ lực nhỏ.
Để mô tả khoảng cách của các bài toán con, một quy tắt tốt đầu tiên là cố gắng
giữ khoảng cách đó càng đơn giản có thể, và sau đó nới rộng nó khi cần thiết. Ví dụ,
khoảng cách giữa các bài toán con mà chúng ta tính toán đến cho việc lập chương trình
cho dây chuyền lắp ráp là cách nhanh nhất từ việc đưa vào nhà máy thông qua trạm S
1,j
và S
2,j
. Khoảng cách bài toán con đó đã làm việc tốt, và không cần phải thử lại một lần
nữa khoảng cách tổng quát của các bài toán con.
Ngược lại, giả định rằng chúng ta đã cố gắng ràng buộc khoảng cách bài toán
con của chúng ta cho bài toán nhân các ma trận thành các sản phẩm ma trận theo mẫu
A
1
A
2
A
j
. Cũng như trước, một sự đặt dấu ngoặc đơn tối ưu phải chia sản phẩm này
giữa A
k
và A
k+1
trong đó 1≤ k ≤ j. Nếu chúng ta không đảm bảo rằng k luôn luôn bằng
j-1, thì chúng ta sẽ tìm thấy rằng chúng ta đã có các bài toán con theo mẫu A
1
A
2
A
k
và
A
k+1
A
k+2
A
j
, và bài toán con sau đó không phải là mẫu A
1
A
2
A
j
. Với bài toán này,
điều cần thiết cho phép các bài toán con của chúng ta biến đổi tại “cả 2 điểm cuối”,
điều đó có nghĩa là cho phép cả i và j để biến đổi trong bài toán con A
i
A
i+1
A
j
.
Cấu trúc con tối ưu biến thiên giữa các vùng bài toán theo 2 cách:
1. Có bao nhiêu bài toán con được sử dụng trong một giải pháp tối
ưu cho một bài toán gốc, và
2. Có bao nhiêu lựa chọn mà chúng ta chúng ta có trong việc xác
định bài toán con nào sử dụng trong một giải pháp tối ưu.
Trong bài toán lập trình cho dây chuyền lắp ráp, một giải pháp tối ưu chỉ dùng
cho 1 bài toán con, nhưng chúng ta phải tính toán đến 2 lựa chọn để xác định một giải
pháp tối ưu. Để tìm cách nhanh nhất thông qua trạm S
i,j
, chúng ta sử dụng hoặc là cách
Trang
14
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
nhanh nhất thông qua S
1,j-1
hoặc là cách nhanh nhất thông qua S
2,j-1
, với mỗi cách ta
trình bày một bài toán con mà chúng ta phải giải quyết một cách tối ưu. Bài toán nhân
chuỗi các ma trận với chuỗi con A
i
A
i+1
A
j
cung cấp như một ví dụ với 2 bài toán con
và j-i lựa chọn. Với một ma trận A
k
cho trước mà chúng ta chia nó thành sản phẩm,
chúng ta có 2 bài toán con – đặt dấu ngoặc đơn cho A
i
A
i+1
A
k
và đặt dấu ngoặc đơn
cho A
k
A
k+1
A
j
– và chúng ta phải giải quyết cả 2 bài toán này một cách tối ưu. Một lần
nữa chúng ta xác định các giải pháp tối ưu cho các bài toán con, chúng ta sẽ chọn các
vị trí thích hợp trong khoảng j-i cho chỉ mục k.
Thông thường, thời gian chạy của một thuật toán quy hoạch động dựa vào sản
phẩm của 2 nhân tố: số lượng tất cả các bài toán con và có bao nhiêu lựa chọn mà
chúng ta tìm thấy cho mỗi bài toán con. Trong bài toán lập trình cho dây chuyền lắp
ráp, chúng ta có Θ (n) tất cả các bài toán con, và chỉ có 2 lựa chọn để xem xét mỗi bài
toán con đó, sinh ra một Θ (n) thời gian chạy. Với bài toán nhân chuỗi các ma trận, có
Θ (n
2
) tất cả các bài toán con, và trong mỗi bài toán con đó chúng ta có nhiều nhất n-1
lựa chọn, cho ra Θ (n
3
) thời gian chạy.
Quy hoạch động dùng cấu trúc con tối ưu theo dạng từ dưới lên. Điều đó có
nghĩa là, đầu tiên chúng ta tìm thấy các giải pháp tối ưu cho các bài toán con, và giải
quyết các bài toán con đó, rồi chúng ta tìm giải pháp tối ưu cho bài toán. Việc tìm ra
một giải pháp tối ưu cho bài toán đòi hỏi một sự lựa chọn giữa các bài toán con để
chúng ta có thể sử dụng các bài toán con đó để giải quyết bài toán. Chi phí của một
giải pháp bài toán thường là các chi phí của bài toán con cộng với một chi phí mà có
thể quy trực tiếp cho sự lựa chọn chính nó. Trong bài toán lập trình cho dây chuyền lắp
ráp, ví dụ, đầu tiên chúng ta giải quyết các bài toán con của việc tìm cách nhanh nhất
thông qua trạm S
1,j-1
và S
2,j-1
, rồi sau đó chúng ta chọn một trong các trạm đó như một
trạm trước S
i,j
. Chi phí cho mỗi sự lựa chọn bản thân nó phụ thuộc vào việc chúng ta
có lựa chọn các dòng giữa j-1 và j hay không; chi phí này là a
i,j
nếu chúng ta đứng trên
cùng một dây chuyền và nếu chúng ta đứng trên hai dây chuyền khác nhau, i khác i',
thì chi phí là t
i’,j-1
+ a
i,j
. Trong bài toán nhân chuỗi các ma trận, chúng ta xác định
những việc đặt dấu ngoặc đơn tối ưu cho các chuỗi con A
i
A
i+1
A
j
, rồi sau đó chúng ta
chọn ma trận A
k
mà tại đó chúng ta chia tách sản phẩm. Chi phí có sự lựa chọn bản
thân nó là số hạng p
i-1
p
k
p
j
.
Trong chương 16, chúng ta sẽ nghiên cứu “các thuật toán tham lam”, chúng có
nhiều điểm tương tự với quy hoạch động. Nói tóm lại, các bài toán áp dụng các thuật
toán tham lam có cấu trúc con tối ưu. Một điểm khác biệt nổi bật giữa các thuật toán
và quy hoạch động là trong các thuật toán tham lam, chúng ta sử dụng cấu trúc con tối
ưu theo dạng từ trên xuống. Thay vì đầu tiên tìm các giải pháp tối ưu cho các bài toán
con rồi sau đó lựa chọn, thì các thuật toán tham lam đầu tiên lại lựa chọn – lựa chọn
được xem là tốt nhất tại thời điểm đó – rồi sau đó giải quyết một đáp số của bài toán
con.
Các điểm tinh tế.
Thứ nhất nên cẩn thận không giả định rằng bài toán con tối ưu được áp dụng
khi không phải là nó. Hãy tính toán theo 2 bài toán mà chúng ta được cho trong một đồ
thị có hướng G = (V, E) và các đỉnh u,v ϵ V.
- Đường đi ngắn nhất không trọng số
(2)
: tìm một đường đi từ
đỉnh u đến đỉnh v sao cho ít cạnh nhất. Như một đường đi phải đơn giản, lúc
Trang
15
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
đó bỏ đi một chu trình từ một đường đi kéo dài tới một đường đi với ít cạnh
hơn.
- Đường đi đơn giản dài nhất không trọng số: tìm một đường đi
đơn giản từ đỉnh u đến đỉnh v sao cho nhiều cạnh nhất. Chúng ta cần tính
đến yêu cầu của tính đơn giản bởi vì nếu không thì chúng ta có thể đi qua
một chu trình càng nhiều lần mà chúng ta muốn để tạo các đường đi với một
số lượng lớn một cách tùy tiện của các cạnh.
Bài toán đường đi ngắn nhất không trọng số trình bày theo cấu trúc con tối ưu.
Giả định rằng u ≠ v, thì bài toán này này không đáng kể. Sau đó bất kỳ đường đi p từ u
đến v phải chứa một đỉnh trung gian, gọi là w. (Chú ý rằng w có thể là u hoặc v.) Theo
cách đó chúng ta có thể phân tích đường đi từ các đường đi con
. Rõ rang rằng, số lượng các cạnh trong p là bằng tổng số các cạnh
trong p
1
với các cạnh trong p
2
. Chúng ta khẳng định rằng nếu p là một đường đi (i.e.,
ngắn nhất) tối ưu từ u đến v, thì p
1
phải là đường đi ngắn nhất từ u tới w. Tại sao như
vậy? Chúng ta dùng luận cứ “cắt và dán”: nếu có một đường đi khác, gọi là p’
1
, từ u
tới w với số cạnh ít hơn p
1
thì chúng ta có thể cắt p
1
ra và dán vào p’
1
để sinh ra một
đường đi với số cạnh ít hơn p, do đó mâu thuẫn với tính tối ưu p’s.
Tương tự, p
2
cũng phải là đường đi ngắn nhất từ w đến v. Như vậy, chúng ta có thể tìm
một đường đi ngắn nhất từ u đến v bằng cách tính đến tất cả các đỉnh trung gian w,
việc tìm một đường đi ngắn nhất từ u tới w và đường đi ngắn nhất từ w tới v, và việc
chọn một đỉnh trung gian w mà nó sinh ra toàn bộ đường đi ngắn nhất. Trong mục
25.2, chúng ta sử dụng một biến của tọa độ đó của cấu trúc con tối ưu để tìm một
đường đi ngắn nhất giữa mỗi cặp của các đỉnh trên một đồ thị có hướng có trọng số.
Thật là lôi cuốn để giả định rằng bài toán của việc tìm đường đi đơn giản dài
nhất không trọng số trình bày theo cấu trúc con tối ưu cũng được. Xét cho cùng, nếu
chúng ta phân tích đường đi đơn giản dài nhất từ các đường đi con
, thì có phải p
1
là đường đi đơn giản dài nhất từ u tới w, và có phải p
2
là đường đi đơn giản dài nhất từ w tới v hay không? Câu trả lời là không! Hình 15.4 là
một ví dụ. Hãy tính đường đi q r t, là đường đi đơn giản dài nhất từ q đến t. Có
phải q r là đường đi đơn giản dài nhất từ q tới r hay không? Không phải, cho đường
đi q s t r là đường đi đơn giản thì nó dài hơn. Vậy thì có phải r t là đường
đi đơn giản dài nhất từ r tới t hay không? Cũng không, cho đường đi r q s t là
đường đi đơn giản thì nó dài hơn.
Hình 15.4
Trang
16
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
Hình 15.4: Một đồ thì có hướng cho thấy rằng bài toán tìm đường đi đơn giản
dài nhất trong đồ thị có hướng không trọng số không có cấu trúc con tối ưu. Đường đi
q r t là đường đi đơn giản dài nhất từ q đến t, nhưng đường đi con q r không
phải là đường đi đơn giản dài nhất từ q đến r, và cũng không phải đường đi con r t
là đường đi đơn giản dài nhất từ r đến t.
Thí dụ này cho thấy với các đường đi đơn giản dài nhất, không chỉ là thiếu cấu
trúc con tối ưu, mà chúng ta còn không thể thu thập một cách tất yếu một giải pháp
“hợp lệ” cho bài toán từ các giải pháp cho các bài toán con. Nếu chúng ta kết hợp các
đường đi đơn giản dài nhất q s t r và r q s t, chúng ta thu được
đường đi q s t r q s t, nó không phải là đơn giản. Thật vậy, bài toán
tìm một đường đi đơn giản dài nhất không trọng số không xuất hiện để có bất kỳ phần
nào cấu trúc con tối ưu. Thuật toán quy hoạch động không hiệu quả với bài toán này
đã được thấy. Thực tế là, bài toán này là NP-đầy đủ, - chúng ta sẽ xem ở chương 34 -
có nghĩa là nó không chắc rằng nó có thể được giải quyết trong đa thức thời gian.
Vậy cái gì thật sự khác nhau giữa cấu trúc con của đường đi đơn giản dài nhất
với cấu trúc con của đường đi ngắn nhất? Mặc dầu hai bài toán con được sử dụng
trong một giải pháp cho một bài toán cho cả hai đường đi ngắn nhất và dài nhất, thì
các bài toán con trong việc tìm đường đi đơn giản dài nhất là không độc lập, trong khi
đó với các đường đi ngắn nhất thì chúng lại độc lập. Cái gì mà chúng ta nghĩ rằng các
bài toán con là độc lập? Chúng ta nghĩ rằng giải pháp cho một bài toán con không ảnh
hưởng đến bài toán con khác của cùng một bài toán. Ví dụ của hình 15.4, chúng ta có
bài toán tìm đường đi đơn giản dài nhất từ q tới t với hai bài toán con: tìm các đường
đi đơn giản dài nhất từ q đến r và từ r đến t. Với bài đầu tiên của các bài toán con này
là chúng ta chọn đường đi q s t r, và chúng ta cũng sử dụng các đỉnh s và t.
Chúng ta có thể không sử dụng các đỉnh này trong bài toán thứ hai, từ đó sự phối hợp
của hai giải pháp cho các bài toán con sẽ sinh ra một đường đi mà đường đi đó không
phải là đơn giản. Nếu chúng ta không thể dùng đỉnh t trong bài toán thứ hai, thì sau đó
chúng ta sẽ không thể giải quyết được nó tất cả, vì t được yêu cầu phải nằm trên đường
đi mà chúng ta tìm, và nó không phải là đỉnh mà tại đó chúng ta “ghép nối” các giải
pháp bài toán con lại với nhau (đỉnh đó là r). việc sử dụng các đỉnh s và t của chúng ta
trong một giải pháp bài toán con ngăn cản chúng được sử dụng trong giải pháp bài
toán con khác. Chúng ta phải dùng ít nhất một trong số chúng để giải quyết bài toán
con khác, tuy nhiên, chúng ta phải dùng cả hai để giải quyết nó một cách tối ưu. Vì
vậy chúng ta nói rằng các bài toán con là không độc lập. Hãy xem xét một cách khác,
việc sử dụng các tài nguyên của chúng ta trong việc giải quyết một bài toán con
(những tài nguyên đó là các đỉnh) đã làm cho (hoàn trả) chúng không dùng được cho
bài toán con khác.
Vậy thì tại sao các bài toán con lại độc lập với việc tìm đường đi ngắn nhất?
Câu trả lời đó là hiển nhiên, vì các bài toán con không chia sẻ các tài nguyên. Chúng ta
khẳng định rằng nếu một đỉnh w là một đường đi ngắn nhất p từ u tới v, thì chúng ta có
thể nối kết bất kỳ đường dẫn ngắn nhất và bất kỳ đường đi ngắn nhất
nào với nhau để sinh ra một đường đi ngắn nhất từ u đến v. Chúng ta được
đảm bảo rằng, ngoài w, không có đỉnh nào có thể xuất hiện trong cả hai đường đi p
1
và
p
2
. Tại sao vậy? Giả sử rằng có đỉnh x≠w xuất hiện trong cả hai đường đi p
1
lẫn p
2
,
chúng ta có thể phân tích p
1
thành và p
2
thành .
Trang
17
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
Bằng cấu trúc con tối ưu của bài toán này, đường đi p có càng nhiều cạnh p
1
và p
2
với
nhau; chúng ta nói rằng p có e cạnh. Bây giờ chúng ta hãy xây dựng một đường đi
từ u đến v. Đường đi này có nhiều nhất e-2 cạnh, mà chúng mâu
thuẫn với giả thiết rằng p là đường đi ngắn nhất. Như vậy, chúng ta được đảm bảo rằng
các bài toán con của bài toán tìm đường đi ngắn nhất là độc lập.
Cả hai bài toán đã xem xét trong mục 15.1 và 15.2 có các bài toán con độc lập.
Trong chuỗi ma trận cấp nhân, các bài toán con là các chuỗi con cấp nhân A
i
A
i+1
A
k
và A
k+1
A
k+2
A
j
. Các chuỗi con này bị tách rời ra, vì vậy không có ma trận nào có thể
chứa đựng được cả hai trong chúng. Trong việc lập trình đường thẳng hội tụ, để quyết
định cách nhanh nhất thông qua trạm S
i,j
chúng ta xem xét các cách nhanh nhất thông
qua các trạm S
1,j-1
và S
2,j-1
. Bởi vì giải pháp cho cách nhanh nhất thông qua trạm S
i,j
của
chúng ta sẽ bao gồm chỉ một trong các giải pháp bài toán con này, bài toán con đó là
độc lập một cách tự nhiên với tất cả các bài toán con khác được sử dụng trong giải
pháp đó.
Sự chồng lấp của các bài toán con. (Các bài toán con gối nhau)
Thành phần thứ hai mà một bài toán tối ưu phải có để quy hoạch động có thể
ứng dụng được là khoảng cách của các bài toán con phải là “nhỏ” trong ngữ cảnh mà
một thuật toán đệ quy cho một bài toán giải quyết các bài toán con tương tự lặp đi lặp
lại, hơn thế nữa thường phát sinh ra các bài toán con mới. Điển hình, tổng số lượng
của sự khác biệt của các bài toán con là một đa thức trong kích thước đầu vào. Khi một
thuật toán đệ quy giải quyết lại một bài toán tương tự lặp đi lặp lại lần nữa, chúng ta
gọi bài toán tối ưu đó có sự chồng lấp của các bài toán con
(3)
. Ngược lại, một bài toán
mà nó thích hợp với phương pháp “chia để trị” thường sinh ra các bài toán mới tại mỗi
bước của đệ quy. Các thuật toán quy hoạch động mang lại thuận lợi của sự chồng lấp
của các bài toán con bằng cách giải quyết mỗi bài toán con một lần và sau đó lưu trữ
giải pháp đó trong một bảng nơi mà nó có thể được tìm thấy khi cần thiết, sử dụng
hằng số thời gian cho mỗi sự tìm kiếm.
Trong mục 15.1, chúng ta đã khảo sát một cách ngắn gọn cách mà một giải
pháp đệ quy cho lập trình dây chuyền lắp ráp tạo ra 2
n-j
tham chiếu tới f
i
[j] với j=1,
2, , n. Giải pháp dạng bảng của chúng ta làm cho thuật toán đệ quy với thời gian số
mũ xuống còn thời gian đường thẳng.
Để minh họa thuộc tính của sự chồng lấp của các bài toán con một cách chi tiết
hơn, chúng ta hãy xem xét lại bài toán nhân chuỗi các ma trận. Tham chiếu lại hình
15.3, để ý rằng thủ tục MATRIX- CHAIN-ORDER lặp đi lặp lại việc tìm kiếm giải
pháp cho các bài toán con ở các hàng thấp hơn khi giải quyết các bài toán con ở các
hàng cao hơn. Ví dụ, mục m[3,4] được tham chiếu tại 4 thời điểm: trong suốt sự tính
toán của m[2,4], m[1,4], m[3,5], và m[3,6]. Nếu m[3,4] được tính toán lại tại mỗi thời
điểm, hơn thế nữa chỉ được tìm kiếm, thì sự tăng trưởng của thời gian chạy sẽ gây nên
đột biến. Để thấy điều này, tính toán theo thủ tục đệ quy (không hiệu quả) xác định
m[i,j], số lượng nhỏ nhất của các phép nhân vô hướng cần thiết để tính toán sản phẩm
chuỗi ma trận A
i j
= A
i
A
i+1
A
j
. Thủ tục này trực tiếp dựa vào phép truy hồi. (15.12)
RECURSIVE-MATRIX-CHAIN (p, i, j)
1 if i = j
Trang
18
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
2 then return 0
3 m[i, j] ∞
4 for k i to j – 1
5 do q RECURSIVE-MATRIX-CHAIN(p, i, k)
+ RECURSIVE-MATRIX-CHAIN(p, k + 1, j)
+ p
i-1
p
k
p
j
6 if q < m[i, j]
7 then m[i, j] q
8 return m[i, j]
Hình 15.5
Hình 15.5: Cây đệ quy với phép tính của RECURSIVE-MATRIX-
CHAIN(p,1,4). Mỗi nút bao gồm các tham số i và j. Các phép tính được thực hiện
trong một cây con in bóng được thay thế bởi một bảng tìm kiếm đơn trong
MEMOIZED-MATRIX-CHAIN(p, 1, 4).
Hình 15.5 hiển thị cây đệ quy đã được xử lý bởi lời gọi RECURSIVE-
MATRIX-CHAIN(p,1,4). Mỗi nút được gán nhãn bởi các giá trị của các tham số i và j.
Quan sát thấy rằng một vài cặp các giá trị xuất hiện nhiều lần.
Nói tóm lại, chúng ta có thể thấy rằng thời gian để tính m[1,n] bằng thủ tục đệ
quy này ít nhất là hàm số mũ với n. Gọi T(n) là thời gian được tạo bởi RECURSIVE-
MATRIX-CHAIN để tính toán việc đặt dấu ngoặc đơn tối ưu của một chuỗi của n ma
trận. Nếu chúng ta giả định rằng sự thực hiện của dòng 1-2 và của dòng 6-7 tạo ra ít
nhất mỗi một đơn vị thời gian, thì sau đó sự kiểm tra của thủ tục sinh ra phép truy hồi.
T(1) ≥ 1,
n-1
T(n) ≥ 1 + ∑ (T(k) + T(n-k) + 1) với n>1,
k=1
Chú ý rằng với i = 1, 2, , n-1, mỗi số hạng T(i) xuất hiện tương ứng với mỗi
một T(k) và T(n-k), và tập n-1 1’s trong phép tính tổng và cũng là số một nằm ở phía
ngoài trước, chúng ta có thể viết lại phép truy hồi là
n-1
T(n) ≥ 2 ∑ T(i) + n (15.3)
i=1
Trang
19
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
Chúng ta sẽ chứng minh rằng T(n) = Ω(2
n
) bằng cách dùng phương pháp thay
thế. Đặc biệt, chúng ta sẽ chỉ ra rằng T(n) ≥ 2
n-1
với tất cả các n ≥ 1. Điều cơ bản này là
dễ dàng, khi T(1) ≥ 1 = 2
0
. Theo quy nạp, với n ≥ 2, chúng ta có:
n-1
T(n) ≥ 2 ∑ 2
i-1
+ n
i=1
n-2
= 2 ∑ 2
i
+ n
i=0
= 2(2
n-1
- 1) + n
= (2
n
- 2) + n
≥ 2
n-1
,
Công thức trên đã hoàn thành việc chứng minh. Theo cách đó, tổng số lượng
của công việc đã được thực hiện bằng cách gọi thủ tục RECURSIVE-MATRIX-
CHAIN(p, 1, n) ít nhất là hàm số mũ với n.
So sánh thuật toán đệ quy từ dưới lên này với thuật toán quy hoạch động từ
dưới lên. Thuật toán sau hiệu quả hơn bởi vì nó mang lại sự thuật lợi của thuộc tính sự
chồng lấp của các bài toán con. Chỉ có Θ(n
2
) bài toán con khác nhau, thuật toán quy
hoạch động giải quyết một cách chính xác mỗi một bài toán con đó. Mặt khác, thuật
toán đệ quy chỉ giải một cách lặp đi lặp lại mỗi bài toán con với mỗi thời gian mà nó
xuất hiện lại trên cây đệ quy. Mỗi khi một cây đệ quy với một giải pháp đệ quy tự
nhiên cho một bài toán bao gồm bài toán con tương tự lặp đi lặp lại, và tổng số lượng
các bài toán con khác nhau là nhỏ, đố là một ý tưởng tốt để thấy rằng nếu quy hoạch
động có thể được thiết lập để làm việc.
Tái thiết một giải pháp tối ưu.
Như một nội dung thiết thực, chúng ta thường lưu trữ lựa chọn mà chúng ta tạo
ra trong mỗi bài toán con trong một bảng vì vậy chúng ta không phải xây dựng lại
thông tin này từ những chi phí mà chúng ta đã lưu trữ. Trong bài toán lập trình cho dây
chuyền lắp ráp, chúng ta lưu trữ trong l
i
[j] trạm trước S
i,j
trong cách nhanh nhất thông
qua S
i,j
. Một sự lựa chọn khác, điền vào bảng f
i
[j] toàn bộ, chúng ta có thể xác định
trạm mà nó nằm trước S
i,j
trong cách nhanh nhất thông qua S
i,j
với một công việc ít hơn
nhiều. Nếu f
1
[j] = f
1
[j-1] + a
1,j
, sau đó trạm S
1,j-1
đi trước S
1,j
trong cách nhanh nhất
thông qua S
1,j
. Mặt khác, nó phải là trường hợp f
1
[j] = f
2
[j-1] + t
2,j-1
+ a
1,j
, và tiếp tục S
2,j-
1
đi trước S
1,j
. Với bài toán lập trình cho dây chuyền lắp ráp, việc tái thiết các trạm
trước chỉ tốn O(1) thời gian cho mỗi trạm, thậm chí không dùng cả bảng l
i
[j].
Tuy nhiên, với bài toán nhân chuỗi các ma trận, bảng s[i, j] lưu lại cho chúng ta
một số lượng công việc đáng kể khi tái thiết một giải pháp tối ưu. Giả sử rằng chúng ta
không dùng bảng s[i, j], chỉ điền vào bảng m[i, j] mà nó bao gồm cả các chi phi bài
toán con tối ưu. Ta có j-i lựa chọn trong việc xác định các bài toán con sử dụng trong
một giải pháp tối ưu cho việc đặt dấu ngoặc đơn A
i
A
i+1
A
j
, và j-i không phải là hằng
số. Vì vậy, nó tốn Θ(j - i) = ω(1) thời gian để tái thiết các bài toán con mà chúng ta
Trang
20
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
chọn với một giải pháp cho một bài toán cho trước. Bằng cách lưu trữ trong s[i, j] chỉ
số của ma trận mà tại đó chúng ta chia tách sản phẩm A
i
A
i+1
A
j
, chúng ta có thể tái
thiết mỗi lựa chọn với O(1) thời gian.
Memoization (lưu trữ)
Có một biến của quy hoạch động mà biến đó thường đưa ra hiệu quả của hướng
tiếp cận quy hoạch động thông thường trong khi duy trì chiến lược từ trên xuống. Ý
tưởng là lưu trữ tự nhiên, nhưng không hiệu quả với thuật toán đệ quy. Do trong quy
hoạch động, chúng ta sử dụng một bảng với các giải pháp bài toán con, nhưng cấu trúc
điều khiển cho việc điền vào bảng là giống với thuật toán đệ quy hơn.
Một thuật toán đệ quy lưu trữ sử dụng việc nhập vào bảng với giải pháp cho
mỗi bài toán con. Mỗi một mục nhập bảng ban đầu chứa một giá trị đặc biệt để chỉ ra
rằng mục nhập chưa được nhập vào. Khi một bài toán con được bắt gặp đầu tiên trong
suốt quá trình thực hiện của thuật toán đệ quy, giải pháp của nó được tính toán và lưu
trữ trong bảng. Với mỗi thời gian sau đó, bài toán con được bắt gặp, giá trị được lưu
trữ trong bảng được tìm kiếm một cách đơn giản và được trả về.
(4)
Dưới đây là một phiên bản lưu trữ của RECURSIVE-MATRIX-CHAIN:
MEMOIZED-MATRIX-CHAIN (p)
1 n length[p] - 1
2 for i 1 to n
3 do for j i to n
4 do m[i, j] ∞
5 return LOOKUP-CHAIN(p, 1, n)
LOOKUP-CHAIN(p, i, j)
1 if m[i, j] < ∞
2 then return m[i, j]
3 if i = j
4 then m[i, j] ∞
5 else for k i to j-1
6 do q LOOKUP-CHAIN(p, i, k)
+ LOOKUP-CHAIN(p,k + 1, j) + p
i-1
p
k
p
j
7 if q < m[i, j]
8 then m[i, j] q
9 return m[i, j]
MEMOIZED-MATRIX-CHAIN, giống như MATRIX-CHAIN-ORDER, chứa một
bảng m[1 n, 1 n] của các giá trị đã tính toán của m[i, j], số lượng nhỏ nhất các phép
nhân vô hướng cần thiết để tính ma trận A
i j
. Mỗi một mục nhập bảng ban đầu chứa
giá trị ∞ để chỉ ra rằng việc nhập đó chưa được nhập vào. Khi việc gọi hàm LOOKUP-
CHAIN(p, i, j) được thực hiện, nếu m[i, j] < ∞ ở dòng 1, thì thủ tục trả về chi phí m[i,
j] được tính toán trước đó một cách đơn giản (hàng 2). Mặt khác, chi phí được tính
trong MEMOIZED-MATRIX-CHAIN, được lưu trữ trong m[i, j], và được trả lại. (Giá
trị ∞ là tiện lợi để sử dụng cho một mục bảng chưa được nhập vì nó là giá trị được sử
dụng để gán giá trị ban đầu m[i, j] ở dòng 3 của thủ tục RECURSIVE-MATRIX-
CHAIN). Theo cách đó, thủ tục LOOKUP-CHAIN(p, i, j) luôn luôn trả về giá trị của
Trang
21
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
m[i, j], nhưng nó chỉ tính nó nếu đó là thời gian đầu tiên khi mà thủ tục LOOKUP-
CHAIN được gọi với các tham số i và j.
Hình 15.5 minh họa cách mà thủ tục MEMOIZED-MATRIX-CHAIN lưu trữ thời gian
so với thủ tục RECURSIVE-MATRIX-CHAIN. Các cây con in bóng trình bày các giá
trị mà chúng được tìm kiếm nhiều hơn tính toán.
Giống như thuật toán quy hoạch động MATRIX-CHAIN-ORDER, thủ tục
MEMOIZED-MATRIX-CHAIN chạy với thời gian O(n
3
). Mỗi một Θ(n
2
) mục nhập
bảng được gán giá trị ban đầu một lần ở hàng 4 của thủ tục MEMOIZED-MATRIX-
CHAIN. Chúng ta có thể phân loại các lời gọi của thủ tục LOOKUP-CHAIN thành 2
cách:
1. Lời gọi khi m[i, j] = ∞, các dòng 3 – 9 được thực hiện, và
2. Lời gọi khi m[i, j] < ∞, thủ tục LOOKUP-CHAIN trả về một cách đơn giản
ở dòng 2.
Có Θ(n
2
) lời gọi của cách đầu tiên, cho mỗi một mục nhập bảng. Tất cả các lời gọi của
cách thứ 2 được tạo ra như các lời gọi đệ quy bởi các lời gọi của cách đầu tiên. Mỗi
khi lời gọi cho trước của thủ tục LOOKUP-CHAIN tạo ra các lời gọi đệ quy, nó tạo ra
O(n) lời gọi. Vì vậy, có tất cả O(n
3
) lời gọi của cách thứ 2. Mỗi một lời gọi của cách
thứ 2 tốn O(1) thời gian, và mỗi lời gọi của cách thứ nhất tốn O(n) thời gian cộng với
thời gian đã chi phí trong các lời gọi đệ quy của nó. Vì vậy, tổng thời gian là O(n
3
).
Theo cách đó, memoization (lưu trữ) xoay quanh một thuật toán Ω(2
n
) thời gian tới
một thuật toán O(n
3
) thời gian.
Nói tóm lại, bài toán nhân chuỗi các ma trận có thể được giải quyết bằng một thuật
toán lưu trữ từ trên xuống hoặc bằng một thuật toán quy hoạch động từ dưới lên với
O(n
3
) thời gian. Cả hai phương pháp đều đem lại sự thuận lợi cho thuộc tính các bài
toán con chồng lấp. Chỉ có Θ(n
2
) tổng số các bài toán con khác nhau, và mỗi một trong
2 cách đó đều tính toán giải pháp cho mỗi vấn đề con một lần. Không có memoization
(lưu trữ), thuật toán đệ quy tự nhiên chạy với hàm số mũ thời gian, vì vậy các bài toán
con đã giải quyết được giải quyết lặp đi lặp lại nhiều lần.
Trong thực tế nói chung, nếu tất cả các bài toán con phải được giải quyết ít nhất đúng
1 lần, thì thuật toán quy hoạch động từ dưới lên thường làm tốt hơn thuật toán lưu trữ
từ trên xuống bằng một thừa số không đổi, bởi vì nó không có liên quan với đệ quy và
ít liên quan hơn với việc sử dụng bảng. Ngoài ra, có một số bài toán mà dạng bảng
thông thường của các bài toán đó truy xuất trong thuật toán quy hoạch động có thể
được khai thác để giảm bớt thời gian hoặc các yêu cầu khoảng cách rải đều hơn. Một
sự lựa chọn khác, nếu một số bài toán con trong khoảng cách bài toán con không cần
thiết phải được giải quyết tất cả, thì giải pháp lưu trữ có thuận lợi cho việc giải quyết
chỉ các bài toán con đó mà chúng được yêu cầu một cách rõ ràng.
Bài tập:
15.3-1: Công việc nào sau đây là cách hiệu quả hơn để xác định số lượng các
phép nhân tối ưu trong bài toán nhân chuỗi các ma trận: liệt kê tất cả các cách của việc
đặt dấu ngoặc đơn cho sản phẩm và tính toán số lượng các phép nhân cho mỗi trường
Trang
22
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
hợp, hay việc chạy thủ tục RECURSIVE-MATRIX-CHAIN? Hãy chứng minh câu trả
lời của bạn.
15.3-2: Hãy vẽ cây đệ quy cho thủ tục MERGE-SORT ở mục 2.3.1 bằng một
mảng gồm 16 phần tử. Giải thích tại sao memoization (lưu trữ) là không hiệu quả
trong việc tăng tốc độ một thuật toán “chia để trị” tốt như là MERGE-SORT.
15.3-3: Hãy xác định một biến của bài toán nhân chuỗi các ma trận mà mục
đích của biến này là đặt dấu ngoặc đơn cho chuỗi các ma trận để cực đại hơn là cực
tiểu, số lượng các phép nhân vô hướng. Có phải bài toán này diễn tả cấu trúc con tối
ưu?
15.3-4: Hãy miêu tả cách mà bài toán lập trình cho dây chuyền lắp ráp có các
bài toán con chồng lấp.
15.3-5: Với phương pháp mà chúng ta giải quyết các bài toán con trước tiên rồi
sau đó chọn một trong số chúng để dùng trong giải pháp tối ưu cho bài toán trong quy
hoạch động. Giáo sư Capulet khẳng định rằng không luôn luôn cần thiết phải giải
quyết tất cả các bài toán con để tìm một giải pháp tối ưu. Bà ấy đề nghị rằng một giải
pháp tối ưu cho bài toán nhân chuỗi các ma trận có thể được tìm thấy bằng cách luôn
chọn một ma trận A
k
mà tại đó chia các sản phẩm con A
i
A
i+1
A
j
(bằng cách chọn k để
cực tiểu hóa con số p
i-1
p
k
p
j
) trước khi giải quyết các bài toán con. Hãy tìm một ví dụ
của bài toán nhân chuỗi các ma trận mà với ví dụ đó thì phương pháp tham lam này
sinh ra một giải pháp gần điểm cực thuận.
Chú thích:
(1): Đây không phải là một lỗi phát âm. Từ này thực sự là memoization, không phải là
memorization. Memoization xuất phát từ memo, vì kỹ thuật này bao gồm việc ghi lại
một giá trị mà chúng ta có thể tìm thấy nó sau đó.
(2): Chúng ta sử dụng thuật ngữ “không trọng số” để phân biệt bài toán này với bài
toán tìm các đường đi ngắn nhất với các cạnh có trọng số, mà chúng ta có thể xem xét
trong chương 24 và 25. Chúng ta có thể sử dụng kỹ thuật tìm kiếm breadth-first (tìm
kiếm theo chiều ngang trước) của chương 22 để giải quyết bài toán không trọng số
này.
(3): Có thể hơi lạ rằng quy hoạch động dựa vào các bài toán con mà chúng vừa độc lập
vừa chồng lấp lẫn nhau. Mặc dù 2 thủ tục này có nghe có vẻ là mâu thuẫn, nhưng
chúng miêu tả 2 khái niệm khác biệt, hơn thế nữa chúng là 2 điểm trên cùng một trục.
Hai bài toán con này của cùng một bài toán là độc lập với nhau nếu chúng không chia
sẻ tài nguyên. Hai bài toán con này là chồng lấp với nhau nếu chúng thực sự là chung
một bài toán mà nó xuất hiện như là một bài toán con của các bài toán khác nhau.
(4): Cách tiếp cận này phỏng đoán rằng tập tất cả các tham số bài toán con có khả năng
được biết trước và mối quan hệ giữa các vị trí bảng với các bài toán con là đã được
thiết lập. Một cách tiếp cận khác là lưu trữ bằng cách sử dụng việc chia nhỏ với các
tham số bài toán con như là các kết quả.
Trang
23
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
15.4. Dãy con chung dài nhất:
Trong ứng dụng sinh học, chúng ta thường so sánh DNA của hai (hoặc nhiềua)
cá thể khác nhau. Một thành phần của DNA bao gồm một chuỗi kí tự của các phân tử
gọi là cơ sở, dựa trên các thành phần cơ bản là adenine, guanine, cytosine và thymine.
Tiêu biểu cho mỗi thành phần này là các kí tự khởi đầu của chúng, một thành phần của
DNA có thể được biểu thị như một chuỗi trên một tập hữu hạn {A, C, G, T}. Ví dụ,
DNA của một cá thể có thể là: S
1
=ACCGGTCGAGTGCGCGGAAGCCGGCCGAA,
trong khi DNA của một cá thể khác lại là S
2
=
GTCGTTCGGAATGCCGTTGCTCTGTAAA. Một trong những mục đích của sự so
sánh hai thành phần của DNA là xác định xem chúng giống nhau như thế nào, cũng là
xem xét mối quan hệ gần gũi giữa hai cá thể. Sự giống nhau (đồng dạng) được xem xét
ở nhiều cách. Chẳng hạn như, chúng ta có thể nói hai DNA giống nhau nếu thành phần
này là dãy con của thành phần kia. Trong ví dụ trên, không phải S
1
cũng không phải S
2
là một dãy con của dãy khác. Theo một cách khác, chúng ta có thể nói rằng hai thành
phần là giống nhau nếu sự khác biệt giữa các kí tự trong hai dãy là ít nhất. Tức là tìm
ra mộtdãy S
3
mà trong đó mỗi thành phần của S
3
xuất hiện đồng thời trong S
1
và S
2
theo đúng trật tự, không nhất thiết phải liên tục. Nếu dãy S
3
tìm được càng dài thì sự
giống nhau giữa S
1
và S
2
càng cao. Trong ví dụ trên, dãy S
3
tìm được dài nhất là
GTCGTCGGAAGCCGGCCGAA.
Dãy con chung dài nhất: Một dãy con được cho bởi một dãy một dãy có độ
dài 0 trở lên.
Về mặt hình thức:
Cho một dãy X = {x
1
, x
2
, …, x
m
}, một dãy Z = {z
1
, z
2,
, z
k
} là dãy con của X
nếu tồn tại một dãy tăng ngặt {i
1
, i
2
, …, i
k
} các chỉ số của X, với j = 1 k, ta có x
ij
= z
j
.
Ví dụ: Z = {A, B, C, D} là một dãy con của X = {A, B, C, B, D, A, B} với các
chỉ số trên dãy X là {2, 3, 5, 7}
- Cho hai dãy X và Y, chúng ta nói rằng Z là một dãy con chung của X
và Y nếu Z là một dãy con của cả X và Y.
Ví dụ:
Cho dãy X = {A, B, C, B, D, A, B}, Y = {B, D, C, B, A}; dãy {B, C, A} là một
dãy con chung của X và Y, nhưng không phải là dãy con chung dài nhất. Bởi vì nó có
độ dài 3, nhưng có dãy {B, C, B, A} cũng là dãy con chung của X và Y có độ dài 4 và
không có một dãy con chung nào của X và Y có độ dài 5. Vậy nên dãy {B, C, B, A} là
dãy con chung dài nhất (viết tắt là LCS-Longest Common Subsequence).
Trong bài toán về dãy con chung dài nhất, chúng ta đã cho hai dãy X={x
1,
x
2
,…,
x
m
} và Y = {y
1
, y
2
, …, y
n
} và mong muốn tìm ra được một dãy con chung dài nhất của
X và Y. Phần này sẽ trình bày bài toán LCS có thể giải quyết trực tiếp bằng phương
pháp Quy hoạch động.
Bước 1: Mô tả một dãy con chung dài nhất.
Một cách để tìm ra dãy con chung dài nhất là liệt kê tất cả các dãy con của X và
kiểm tra xem mỗi dãy con có phải là dãy con của Y hay không, từ đó tìm ra dãy con
chung dài nhất. Mỗi dãy con như thế sẽ nhận lần lượt các phần tử từ 1, 2, …, đến m;
và như vậy có đến 2
m
dãy con như thế, do đó việc giải quyết vấn đề này đòi hỏi một
thời gian rất lớn, đặc biệt khi mà dãy X dài.
Trang
24
Tiểu luận PT&TKTT: Thuật toán Quy hoạch động_________________________________Nhóm 3
Dãy con chung dài nhất có một thuộc tính cấu trúc con tối ưu.
Định lý (về Tính tối ưu của dãy con chung dài nhất)
Cho X = {x
1
, x
2
, …, x
m
} và Y = {y
1,
y
2
, …, y
n
}; Z = {z
1
, z
2
, …, z
k
} là một dãy
con chung dài nhất của X và Y.
1. Nếu x
m
= y
n
thì z
k
= x
m
= y
n
và Z
k-1
là một dãy con chung dài nhất của
X
m-1
và Y
n-1
.
2. Nếu x
m
≠ y
n
thì z
k
≠ x
m
và Z là dãy con chung dài nhất của X
m-1
và Y
n
.
3. Nếu x
m
≠ y
n
thì z
k
≠ y
n
và Z là dãy con chung dài nhất của X và Y
n-1.
Chứng minh:
(1). Nếu z
k
≠ x
m
thì chúng ta có thể chèn thêm x
m
= y
n
vào Z để tạo thu được một dãy
con chung dài nhất của X và Y độ dài k+1, trái với giả thuyết rằng Z là một dãy con
chung dài nhất của X và Y. Vì vậy, chúng ta phải có z
k
= x
m
= y
n
.
Bây giờ, xét dãy Z
k-1
có độ dài k-1 là dãy con chung của X
m-1
và Y
n-1
. Chúng ta
cần tìm ra dãy con chung dài nhất. Giả sử ngược lại rằng có một dãy con chung dài
nhất W của X
m-1
và Y
n-1
có độ dài lớn hơn k-1. Khi đó, thêm x
m
= y
n
vào W sẽ nhận
được một dãy con chung của X và Y có độ dài lớn hơn k, điều này trái với giả thuyết.
(2). Nếu z
k
≠ x
m
thì Z là một dãy con chung của X
m-1
và Y. Nếu có một dãy con chung
W của X
m-1
và Y thì sẽ có độ dài lớn hơn k, vì thế W cũng là một dãy con chung của
X
m
và Y, trái với giả thuyết rằng Z là dãy con chung dài nhất của X và Y.
(3). Việc chứng minh (3) có thể suy ra từ (2) (đối xứng với (2)).
Bước 2: Giải pháp đệ quy:
Định lý 15.5 chỉ ra rằng có một hoặc hai bài toán con để giải quyết khi tìm một dãy
con chung dài nhất của X = {x
1
, x
2
, …, x
m
} và Y = {y
1
, y
2
, …, y
n
}.
- Nêu x
m
=y
n
, chúng ta phải tìm ra một dãy con chung dài nhất của X
m-1
và Y
n-1
. Thêm x
m
=y
n
vào LCS trên ta sẽ thu được LCS của X và Y.
- Nếu x
m
≠ y
n
thì chúng ta phải giải quyết hai bài toán:
o Tìm ra một LCS của X
m-1
và Y, tìm ra một LCS của X và Y
n-1
.
o LCS nào dài hơn chính là LCS của X và Y.
Chúng ta thấy rằng có sự chung nhau giữa hai vấn đề con trên trong CLS. Để
tìm ra một CLS của X và Y, chúng ta có thể cần phải tìm CLS của X và Y
n-1
và CLS
của X
m-1
và Y. Nhưng mỗi vấn đề nhỏ này lại nãy sinh các vấn đề nhỏ khác.
Ta thiết lập một ma trận C như sau: mỗi phần tử c[i,j] xác định độ dài của LCS
của các xâu X
i
và Y
j
. Nếu i = 0 hoặc j = 0, tức là một trong hai dãy có độ dài bằng 0,
và dĩ nhiên trong trường hợp này LCS của X và Y có độ dài bằng 0. Ta xác định c[i,j]
như sau:
−−
+=
j])1,c[i1],jmax(c[i,
11]-j1,-c[i
0
],[ jic
Trang
25
Nếu i=0 hoặc j=0
Nếu i,j>0 và x
i
=y
j
(15.14)
Nếu i,j>0 và x
i
≠y
j