Bài toán quy hoạch động Trong toán học và khoa học máy tính, quy hoạch động dynamicprogramming là một phương pháp hiệu quả giải những bài toán tối ưu có batính chất sau đây: Bài toán l
Trang 1QUY HOẠCH ĐỘNG
Trường THPT Chuyên Biên Hòa – Hà Nam
1 Bài toán quy hoạch động
Trong toán học và khoa học máy tính, quy hoạch động (dynamicprogramming) là một phương pháp hiệu quả giải những bài toán tối ưu có batính chất sau đây:
Bài toán lớn có thể phân rã thành những bài toán con đồng dạng,những bài toán con đó có thể phân rã thành những bài toán nhỏ hơn nữa …(recursive form)
Lời giải tối ưu của các bài toán con có thể sử dụng để tìm ra lời giải tối
ưu của bài toán lớn (optimal substructure)
Hai bài toán con trong quá trình phân rã có thể có chung một số bàitoán con khác (overlapping subproblems)
Tính chất thứ nhất và thứ hai là điều kiện cần của một bài toán quyhoạch động Tính chất thứ ba nêu lên đặc điểm của một bài toán mà cách giảibằng phương pháp quy hoạch động hiệu quả hơn hẳn so với phương pháp giải
đệ quy thông thường
Với những bài toán có hai tính chất đầu tiên, chúng ta thường nghĩ đếncác thuật toán chia để trị và đệ quy: Để giải quyết một bài toán lớn, ta chia nó
ra thành nhiều bài toán con đồng dạng và giải quyết độc lập các bài toán conđó
Khác với thuật toán đệ quy, phương pháp quy hoạch động thêm vào cơchế lưu trữ nghiệm hay một phần nghiệm của mỗi bài toán khi giải xongnhằm mục đích sử dụng lại, hạn chế những thao tác thừa trong quá trình tínhtoán
2 Cách giải một bài toán quy hoạch động
Việc giải một bài toán quy hoạch động phải qua khá nhiều bước, ta cóthể hình dung:
Trang 2Quy hoạch động = Chia để trị + Cơ chế lưu trữ nghiệm để sử dụng lại (Dynamic Programming = Divide and Conquer + Memoization)
Không có một “thuật toán” nào cho chúng ta biết một bài toán có thểgiải bằng phương pháp quy hoạch động hay không? Khi gặp một bài toán cụthể, chúng ta phải phân tích bài toán, sau đó kiểm chứng ba tính chất của mộtbài toán quy hoạch động trước khi tìm lời giải bằng phương pháp quy hoạchđộng Lớp các bài toán giải bằng quy hoạch động là:
• Bài toán tối ưu: Max / Min
con - tìm công thức truy hồi
Sau khi xây dựng công thức truy hồi, ta phải phân tích xem tại mỗi
bước tính nghiệm của một bài toán, chúng ta cần lưu trữ bao nhiêu bài toán
con và với mỗi bài toán con thì cần lưu trữ toàn bộ nghiệm hay một phần nghiệm Từ đó xác định lượng bộ nhớ cần thiết để lưu trữ, nếu lượng bộ nhớ
cần huy động vượt quá dung lượng cho phép, chúng ta cần tìm một công thứckhác hoặc thậm chí, một cách giải khác không phải bằng quy hoạch động
Một điều không kém phần quan trọng là phải chỉ ra được bài toán nào
cần phải giải trước bài toán nào, hoặc chí ít là chỉ ra được khái niệm bài toán
này nhỏ hơn bài toán kia nghĩa là thế nào, xác định được một tập các bài toán
Trang 3nhỏ nhất có thể giải trực tiếp, nghiệm của chúng sau đó được dùng làm cơ sởgiải những bài toán lớn hơn
Trong đa số các bài toán quy hoạch động, nếu bạn tìm được đúng côngthức truy hồi và xác định đúng tập các bài toán cơ sở thì coi như phần lớncông việc đã xong Việc tiếp theo là cài đặt chương trình giải công thức truyhồi:
Cuối cùng là chỉ ra nghiệm của bài toán ban đầu Nếu bảng phương ánlưu trữ toàn bộ nghiệm của các bài toán thì chỉ việc đưa ra nghiệm của bàitoán ban đầu, nếu bảng phương án chỉ lưu trữ một phần nghiệm, thì trong quátrình tính công thức truy hồi, ta để lại một “manh mối” nào đó (gọi là vết) đểkhi kết thúc quá trình giải, ta có thể truy vết tìm ra toàn bộ nghiệm
Sau đây tôi sẽ trình bày một số bài toán quy hoạch động cụ thể mà giáoviên có thể dùng trong quá trình giảng dạy thực tế ở trường cho học sinh:
3 Một số bài toán giải bằng quy hoạch động
3.1 Sub3Sequences
Dãy con của một dãy A cho trước là một dãy thu được bằng cách xóa
đi một số phần tử của dãy A Mỗi dãy số là dãy con của chính nó Dãy rỗng
là dãy con của mọi dãy bất kỳ
Cho trước 3 dãy số A, B, C Ta nói X là dãy con chung của A, B, C khi
X là dãy con của cả 3 dãy đó
Yêu cầu: Cho trước 3 dãy số A, B, C Tìm dãy con chung có chiều dài
Trang 4Dòng thứ 3ghi các số nguyên ck (|ck|<100 000; 0<k<100) là giá trị củacác phần tử của dãy C.
Các số cách nhau ít nhất bởi một khoảng trắng
Dữ liệu ra: ghi ra file Sub3Seq.out gồm một số nguyên L cho biết
chiều dài của dãy con chung dài nhất của 3 dãy đã cho
- Gọi na, nb, nc lần lượt là chiều dài của các dãy số A, B, C
- Gọi L[i,j,k] là chiều dài dãy con chung dài nhất của 3 dãy con a1, a2, , ai A
Trang 5- Công thức truy hồi:
a, b, c: array [1 max] of longint;
pa: array[1 max] of longint;
Trang 6while not eoln(f) do
Trang 7i:=m; j:=n; k:=p;
while (i>0) and (j>0) and (k>0) do
begin
Trang 8if (a[i]=b[j]) and (b[j]=c[k]) then
begin
inc(dem); pa[dem]:=i;
dec(i); dec(j); dec(k);
end
else if L[i,j,k]=L[i-1,j,k] then dec(i)
else if L[i,j,k]= L[i,j-1,k] then dec(j)
else if L[i,j,k]= L[i,j,k-1] then dec(k);
Trang 9Bạn là người thắng cuộc trong một cuộc thi do một hãng hàng khôngtài trợ và phần thưởng là một chuyến du lịch do bạn tuỳ chọn Có n thành phố
và chúng được đánh số từ 1 tới n theo vị trí từ Tây sang Đông (không có haithành phố nào ở cùng kinh độ), có m tuyến bay hai chiều do hãng quản lý,mỗi tuyến bay nối giữa hai thành phố trong số n thành phố đã cho Chuyến dulịch của bạn phải xuất phát từ thành phố 1, bay theo các tuyến bay của hãngtới thành phố n và chỉ được bay từ Tây sang Đông, sau đó lại bay theo cáctuyến bay của hãng về thành phố 1 và chỉ được bay từ Đông sang Tây Hànhtrình không được thăm bất kỳ thành phố nào quá một lần, ngoại trừ thành phố
1 là nơi bắt đầu và kết thúc hành trình
Yêu cầu: Tìm hành trình du lịch qua nhiều thành phố nhất.
Input
Dòng 1 chứa số thành phố n, và số tuyến bay m
Dòng tiếp, mỗi dòng chứa thông tin về một tuyến bay: gồm chỉ số hai thành phố tương ứng với tuyến bay đó
Trang 10Ta có thể đặt một mô hình đồ thị G = (V, E) với tập đỉnh V là tập cácthành phố và tập cạnh E là tập các tuyến bay Bài toán này nếu không córàng buộc về hành trình Tây–Đông-Tây thì có thể quy dẫn về bài toán tìmchu trình Hamilton (Hamilton Circuit) trên đồ thị Nhưng bài toán này nhờ
có ràng buộc về hướng đi nên chúng ta có thể xây dựng một thuật toán chokết quả tối ưu với độ phức tạp O(n3) Tại IOI’93*, bài toán du lịch Đông –Tây này được coi là bài toán khó nhất trong số bốn bài toán của đề thi
Dễ thấy rằng hành trình đi qua nhiều thành phố nhất cũng là hành trình đibằng nhiều tuyến bay nhất mà không có thành phố nào thăm qua hai lầnngoại trừ thành phố 1 là nơi bắt đầu và kết thúc hành trình Với hai thànhphố i và j trong đó i<j, ta xét các đường bay xuất phát từ thành phố i, baytheo hướng Tây tới thành phố 1 rồi bay theo hướng Đông tới thành phố j saocho không có thành phố nào bị thăm hai lần
Nếu tồn tại đường bay như vậy, ta xét đường bay qua nhiều tuyến baynhất, ký hiệu (i 1 j) và gọi f[i, j] là số tuyến bay dọc theo đường baynày
Nếu không tồn tại đường bay thoả mãn điều kiện đặt ra, ta coi f[i,j ]= -1Chú ý rằng chúng ta chỉ quan tâm tới các f[i, j] với i<j , tức là thành phố i ởphía Tây thành phố j mà thôi
Nếu tính được các f[i, n] thì tua du lịch cần tìm sẽ gồm các tuyến bay trênmột đường bay (i1 n) nào đó ghép thêm tuyến bay (n, i), tức là số tuyếnbay (nhiều nhất) trên tua du lịch tối ưu cần tìm sẽ là max{f[i, n]}+1 Vấn đềbây giờ là phải xây dựng công thức tính các f[i, j]
Trang 11Với i < j, xét đường bay (i1 j ), đường bay này sẽ bay qua một thành phố
k nào đó trước khi kết thúc tại thành phố j Có hai khả năng xảy ra:
Thành phố k nằm phía đông (bên phải) thành phố i (k>i), khi đóđường bay i1 j có thể coi là đường bay i1 k ghép thêm tuyếnbay (k, j) Vậy trong trường hợp này f[i, j] = f(k)[i, j] = f[k, i] + 1
Thành phố k nằm phía tây (bên trái) thành phố i (k < i), khi đó đườngbay i1 j có thể coi là đường bay k1 i theo chiều ngược lại rồighép thêm tuyến bay (k, j) Vậy trong trường hợp này f[i, j] = f(k)[i, j]
= f[i, k] + 1
Hình: Đường đi từ i1 j và hai vị trí của thành phố k
Vì tính cực đại của f[i, j ], ta suy ra công thức truy hồi:
F[i, j] = max {f(k)[i, j]} (1)trong đó 1<=k<j; k≠i; f(k)[i, j] ≠ -1, (k,j) là một chuyến bay
Các giá trị f(k)[i, j] trong công thức (1) được tính bởi:
Các phần tử của bảng f sẽ được tính theo từng hàng từ trên xuống vàtrên mỗi hàng thì các phần tử sẽ được tính từ trái qua phải Các phần tử hàng
1 của bảng f (f[1, j]) sẽ được tính trước để làm cơ sở quy hoạch động
Bài toán tính các giá trị f[1, j] lại là một bài toán quy hoạch động: f[1,j] theo định nghĩa là số tuyến bay trên đường bay Tây Đông qua nhiềutuyến bay nhất từ 1 tới j Đường bay này sẽ bay qua thành phố k nào đó
Trang 12trước khi kết thúc tại thành phố j Theo nguyên lý bài toán con tối ưu, ta cócông thức truy hồi:
F[1, j] = max {f[1, k]}+1 (2)
với k<j, f[1,k] ≠ -1, và (k, j) là một chuyến bay
Cơ sở quy hoạch động để tính các f[1, j] chính là f[1, 1] =0
Quy trình giải có thể tóm tắt qua hai bước chính:
a: array[1 max, 1 max] of Boolean;
f: array[1 max, 1 max] of Integer;
trace: array[1 max, 1 max] of Integer;
Trang 13Result := value > target;
if Result then target := value;
end;
procedure Optimize; //Giải công thức truy hồi
var
i, j, k: Integer;
Trang 14for k := i + 1 to j - 1 do //k nằm phía Đông i
if a[k, j] and (f[i, k] <> -1) and
Maximize(f[i, j], f[i, k] + 1) then
trace[i, j] := k;
for k := 1 to i - 1 do //k nằm phía Tây i
if a[k, j] and (f[k, i] <> -1) and
Trang 15//Tua du lịch cần tìm sẽ là gồm các tuyến bay trên đường bay k
→1→j=n ghép thêm tuyến (i, n)
//Chúng ta tìm đường bay từ Đông→ Tây p: i→1 và q: j→ 1 gồm các tuyến bay trên đường bay i→ 1 →j
p.nCities := 1; p.c[1] := i; //L ưu trữ thành phố cuối cùng của đường
k := trace[i, j]; //Xét thành phố k đứng liền trư ớc j
Inc(nCities); c[nCities] := k; //đưa k vào đường q
Trang 16Inc(nCities); c[nCities] := k; // đưa k vào đương p
WriteLn('The best tour: ');
WriteLn('Number of cities: ', LongestTour + 1);
// Để in ra tua du lịch tối ưu, ta sẽ in ghép đường:
//In ngược đường p để có đ ừơng đi T ây → Đông: 1 →i
//In xuôi q để có đường đi Đông→ Tây: n→ 1
for i := p.nCities downto 1 do Write(p.c[i], ' ');
for i := 1 to q.nCities do Write(q.c[i], ' ');
Trang 17Ô nằm trên giao của dòng i và cột j được gọi là ô (i,j) Trên mỗi ô (i,j)
có ghi một số nguyên aij , i =1, 2, 3, 4; j =1, 2, , n Một cách chọn ô là việcxác định một tập con khác rỗng S của tập tất cả các ô của bảng sao cho không
có hai ô nào trong S có chung cạnh Các ô trong tập S được gọi là ô đượcchọn, tổng các số trong các ô được chọn được gọi là trọng lượng của cáchchọn Tìm cách chọn sao cho trọng lượng là lớn nhất
Ví dụ: Xét bảng với n=3 trong hình vẽ dưới đây:
Cách chọn cần tìm là tập các ô S = {(3,1), (1,2), (4,2), (3,3)} với trọng lượng
32
Dữ liệu: SELECT.INP
Dòng đầu tiên chứa số nguyên dương n là số cột của bảng
Cột thứ i trong số 4 dòng tiếp theo chứa n số nguyên là n số trên hàng icủa bảng
Kết quả: SELECT.OUT
Trang 18 Gồm 1 dòng duy nhất là trọng lượng của cách chọn tìm được
-1 9 3-4 5 -6
7 8 9
9 7 2
32
Gợi ý: Mỗi cột có 4 dòng nên có thể dùng biến x có 4 bit nhị phân để mô tả
trạng thái chọn của cột i: bit thứ k bằng 1 (hoặc 0) tương ứng với ô dòng thứ
k của cột được (không được) chọn
Gọi F[i,x] là trọng lượng lớn nhất nếu xét từ cột 1 đến cột i và trạngthái chọn của cột i được biểu diễn bằng biến x Công thức Quy hoach độnglà:
F[i,x] = max ( F[i-1,x’] + sum(i,x) )Trong đó
- x và x’ là hai trạng thái chọn của 2 cột liên tiếp nhau (i và i-1) do
đó 2 trạng thái phải thỏa mãn điều kiện không có 2 ô nào đượcchọn kề nhau
- sum(i,x) là trọng lượng ứng với trạng thái chọn x của cột i
3.3.4 Số lớn nhất
Cho 2 xâu:
Trang 19X = x1x2 xm (Với xi là các kí tự số từ ‘0’ đến ‘9’)
Y = y1y2 yn.( Với yj là các kí tự số từ ‘0’ đến ‘9’) (m, n <= 250)
Ta gọi: Z = z1z2 zk là xâu chung của 2 xâu X, Y nếu xâu Z nhận được từ xâu
X bằng cách xoá đi một số kí tự và cũng nhận được từ xâu Y bằng cách xoá
Kết quả ra file: String.out
- Nếu không có cách xóa thì ghi số -1
- Nếu có cách xóa thì ghi số Z lớn nhất có thể nhận được
String.inp String.out
19012304034012
34
Gợi ý:
- Tìm dãy con chung dài nhất bằng quy hoạch động: gọi L[i, j] là
độ dài của dãy con chung dài nhất khi dãy X gồm các phần tử
tử i tới length(x), dãy thứ 2 gồm các phần tử từ j tới length(y),
ta có: L[i,j]:= max(L[i+1,j+1] + ord(X[i]=Y[j]), L[i, j+1],L[i+1, j])
Trang 20Tìm chữ số k nhận giá trị m-1 tới 1 (tính từ bên phải dãy conchung sang trái)
{
Duyệt chữ số ch từ 9 tới 1
{ cho u tăng từ i+1 cho tới khi x[u]=ch
Cho v tăng từ j+1 tới khi y[v]=ch
Nếu L[u, v]= k thì ch là chữ số hàng k (tính
từ phải sang) }}
Chú ý: Với bài toán trên ta cũng có thể hỏi:
Hãy tìm xâu con chung của X và Y sao cho xâu con nhận được có trọng lượng lớn nhất.
Trọng lượng của một xâu Z tùy ý với Z = z1z2 zn (z1, z2, , zn là các sốnguyên) được tính bằng z1+z2+ +zn
Gợi ý: Gọi W[i, j] là trọng lượng lớn nhất của xâu con chung của 2 xâu X và
Trang 21 Gợi ý:
Gọi Xi j là biểu thức chứa xi/x+1/ / xj với 1i j n
Pi j là biểu thức của Xi j sau khi thêm cặp dấu ngoặc vào
C(Pi j) là giá trị của biểu thức Pi j
Với X1 n sẽ có thể tách ra làm 2 dãy con là X1 k và Xk+1 n với 1 k n-1Khi đó C(P1 n) = (( ))
n k
k P C
P C
Sử dụng thuật toán quy hoạch động:
Gọi M[i, j] là giá trị lớn nhất của một biểu thức được tạo ra từ Xi j khi đặt cặpdấu ngoặc vào một vị trí nào đó trong đoạn này
Gọi m[i, j] là giá trị nhỏ nhất của một biểu thức được tạo ra từ Xi j khi đặt cặpdấu ngoặc vào một vị trí nào đó trong đoạn này
Ta sẽ có:
Các bạn đồng nghiệp có thể tham khảo cách cài đặt cũng như một số bài toánquy hoạch động hay khác trong địa chỉ sau: http://www.google.com.vn/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=4&ved=0CD8QFjAD&url=http%3A%2F%2Fwww.dei.unipd.it%2F~geppo%2FDA2%2FDOCS
Trang 22phải dựa vào đặc trưng của từng bài toán cũng như kinh nghiệm của ngườilàm.
Hi vọng bài viết này hữu ích đối với các bạn đồng nghiệp trong quátrình dạy quy hoạch động cho học sinh Vì thời gian có hạn cũng như kinhnghiệm giảng dạy còn ít nên tôi mới trình bày thuật toán ở mức cơ bản,việc cài đặt thuật toán có thể chưa tối ưu Rất mong các bạn đồng nghiệpgóp ý để bài viết này sẽ được hoàn thiện hơn