Professional Documents
Culture Documents
Phương
Đối với các bạn yêu thích môn lập trình thì có lẽ giải thuật qui hoạch
động tương đối quen thuộc trong việc giải quyết các vấn đề tin học. Tuy
nhiên, sẽ thật là khó để có thể tìm được cơ cở và công thức cho việc sử dụng
quy hoạch động. Chính vì vấn đề này, quy hoach động lại trở thành không phổ
biến. Đối với những bài toán như vậy, chúng ta lại cố gắng đi tìm cách giải
khác ví dụ như vét cạn hay tham lam....điều đó thật là dở!
Trong phần đề tài này nhóm chúng em sẽ trình bày về phương pháp quy
hoach động.Tuy nhiên nhóm chúng em không thể trình bày một cách hoàn
chỉnh về quy hoạch động mà chỉ giới thiệu về phương pháp, cách dùng quy
hoạch động để thiết kế một số kĩ thuật giải cho một số bài toán và làm rõ hơn
tính ưu việt của kĩ thuật Bottom-up.Và mong rằng sau bài báo cáo này, các
bạn sẽ yêu thích giải thuật này hơn.
Do thuật toán quy hoạch động chúng em mới được tiếp xúc lần đầu và quy
hoạch động là thuật toán còn khá mới đối với sinh viên chúng em nên chắc
chắn sẽ không thể nào tránh khỏi những sai sót và có những phần chưa đạt yêu
cầu. Chúng em rất mong nhận được ý kiến đóng góp của cô và các bạn để có
thể hoàn chỉnh nội dung cho những lần làm bài tiếp!.
SVTH:Nhóm 6 -1
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
hình1
Hình1: Sơ đồ bài toán con cho dãy Fibonacci, mô tả quan hệ giữa các bài toán
con gối nhau. Nói rằng một bài toán có các bài toán con trùng nhau có nghĩa
SVTH:Nhóm 6 -2
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
là mỗi bài toán con đó được sử dụng để giải nhiều bài toán lớn hơn khác nhau.
Ví dụ, trong dãy Fibonacci, F3 = F1 + F2 và F4 = F2 + F3, khi tính mỗi số đều
phải tính F2. Vì tính F5 cần đến cả F3 và F4, một cách tính F5 có thể sẽ phải
tính F2 hai lần hoặc nhiều hơn. Điều này áp dụng mỗi khi có mặt các bài toán
con gối nhau: Một cách tiếp cận “ngây thơ” có thể tốn thời gian tính toán lại
lời giải tối ưu cho các bài toán con mà nó đã giải.
Để tránh việc đó, ta lưu trữ lời giải của các bài toán con đã giải. Do vậy,
nếu sau này ta cần giải lại chính bài toán đó, ta có thể lấy và sử dụng kết quả
đã được tính toán. Hướng tiếp cận này được gọi là lưu trữ (trong tiếng Anh
được gọi là memoization, không phải memorization, dù từ này cũng hợp
nghĩa). Nếu ta chắc chắn rằng một lời giải nào đó không còn cần thiết nữa, ta
có thể xóa nó đi để tiết kiệm không gian bộ nhớ. Trong một số trường hợp, ta
còn có thể tính lời giải cho các bài toán con mà ta biết trước rằng sẽ cần đến.
Tóm lại, quy hoạch động sử dụng:
+ Các bài toán con gối nhau
+ Cấu trúc con tối ưu
*Quy hoạch động thường dùng một trong hai cách tiếp cận:
+ Top-down (Từ trên xuống): Bài toán được chia thành các bài toán
con, các bài toán con này được giải và lời giải được ghi nhớ để phòng trường
hợp cần dùng lại chúng. Đây là đệ quy và lưu trữ được kết hợp với nhau.
+ Bottom-up (Từ dưới lên): Tất cả các bài toán con có thể cần đến đều
được giải trước, sau đó được dùng để xây dựng lời giải cho các bài toán lớn
hơn. Cách tiếp cận này tốt hơn về không gian bộ nhớ dùng cho ngăn xếp và số
lời gọi hàm. Tuy nhiên, đôi khi việc xác định tất cả các bài toán con cần thiết
cho việc giải quyết bài toán cho trước không được trực giác lắm.
SVTH:Nhóm 6 -3
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
SVTH:Nhóm 6 -4
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
hệ thống và cũng phụ thuộc vào cách thức đạt được giá trị g trong từng giai
đoạn mà mỗi cách thức được gọi là điều khiển. Đại lượng g thường được gọi
là hàm mục tiêu và quá trình đạt được giá trị tối ưu của g được gọi là quá trình
điều khiển tối ưu.
Bellman phát biểu nguyên lý tối ưu (cũng gọi là nguyên lý Bellman) mà
ý tưởng cơ bản là như sau: "Với mỗi quá trình điều khiển tối ưu, đối với trạng
thái ban đầu A0, với mọi trạng thái A trong quá trình đó, phần quá trình kể từ
trạng thái A xem như trạng thái bắt đầu cũng là tối ưu".
Chú ý rằng nguyên lý này được thừa nhận mà không chứng minh.
Phương pháp tìm điều khiển tối ưu theo nguyên lý Bellman thường được
gọi là quy hoạch động. Thuật ngữ này nói lên thực chất của quá trình điều
khiển là động:Có thể trong số bước đầu tiên lựa chọn điều khiển tối ưu dường
như không tốt nhưng chung cả quá trình lại là tốt nhất.
Ta có thể giải thích ý này qua bài toán sau: Cho một dãy số nguyên
A1,A2,….An. Hãy tìm cách xóa đi một số ít nhất số hạng để dãy còn lại là dãy
đơn điệu hay nói cách khác hãy chọn một số nhiều nhất các số sao cho dãy B
gồm các số hạng đó theo trình tự xuất hiện trong dãy A là đơn điệu.
Quá trình chọn dãy B được điều khiển qua N giai đoạn để đạt được mục
tiêu là số lượng số hạng của dãy B là nhiều nhất, điều khiển ở giai đoạn i thể
hiện việc chọn hay không chọn dãy Ai vào dãy B.
Giả sử dãy đã cho là 1 8 10 2 4 6 7. Nếu ta chọn lần lượt 1, 8, 10 thì chỉ
chọn được 3 số hạng nhưng nếu bỏ qua 8 và 10 thì ta chọn được 5 số hạng 1,
2, 4, 6, 7.
Khi giải một số bài toán bằng cách "chia để trị", chuyển việc giải bài
toán kích thước lớn về việc giải nhiều bài toán cùng kiểu có kích thước nhỏ
hơn thì các thuật toán này thường được thể hiện bằng các chương trình con đệ
quy. Khi đó, trên thực tế, nhiều kết quả trung gian phải được tính nhiều lần.
Nói các khác phương pháp quy hoạch động đã thể hiện sức mạnh của
nguyên lý chia để trị đến cao độ.
Trong một số trường hợp, khi giải một bài toán A, trước hết ta tìm họ bài
toán A(p) phụ thuộc tham số p (có thể là một véc tơ) mà A(p0)=A với p0 là
SVTH:Nhóm 6 -5
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
trạng thái ban đầu của bài toán A. Sau đó tìm cách giải họ bài toán A(p) với
tham số p bằng cách áp dụng nguyên lý tối ưu của Bellman. Cuối cùng cho
p=p0 sẽ nhận được kết quả của bài toán A ban đầu.
Các thuật ngữ dùng trong quy hoạch động:
Bài toán giải theo phương pháp quy hoạch động gọi là bài toán quy
hoạch động.
Công thức phối hợp nghiệm của các bài toán con để có nghiệm của bài toán
lớn gọi là công thức truy hồi của quy hoạch động.Tập các bài toán có ngay lời
giải để từ đó giải quyết các bài toán lớn hơn gọi là cơ sở quy hoạch
động.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.
2. Các bước thực hiện quy hoạch động
Để giải bài toán bằng quy hoạch động, ta cần phải tiến hành các bước
sau:
Bước 1: Lập hệ thức ( tìm nghiệm của bài toán con đơn giản và tìm ra
công thức xây dựng nghiệm của bài toán con thông qua nghiệm của các bài
toán con cỡ nhỏ hơn)
Dựa vào nguyên lý tối ưu tìm cách chia quá trình giải bài toán thành từng
giai đoạn, sau đó tìm hệ thức biểu diễn tương quan quyết định của bước xử lý
với các bước đã xử lý trước đó. Hoặc tìm cách phân rã bài toán thành các "bài
toán con" tương tự có kích thước nhỏ hơn, tìm hệ thức nêu quan hệ giữa kết
quả bài toán kích thước đã cho với các kết quả của các "bài toán con" cùng
kiểu có kích thước nhỏ hơn của nó nhằm xây dựng công phương trình truy
toán (dạng hàm hoặc thủ tục đệ quy).
*Cách xây dựng công thức truy toán: Ta chia việc giải bài toán thành n giai
đoạn. Mỗi giai đoạn i có trạng thái ban đầu là t(i) và chịu tác động điều khiển
d(i) sẽ biến thành trạng thái tiếp theo t(i+1) của giai đoạn i+1. (i=1,2,…n-1).
Theo nguyên lý tối ưu của Bellman thì việc tối ưu giai đoạn cuối cùng không
làm ảnh hưởng đến kết quả toàn bài toán. Với trạng thái ban đầu là r(n) sau
khi làm giai đoạn n tốt nhất ta có trạng thái ban đầu của giai đoạn n-1 là t(n-1)
và tác động điều khiển của giai đoạn n-1 là d(n-1), ta có thể tiếp tục xét đến
SVTH:Nhóm 6 -6
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
giai đoạn n-1. Sau khi tối ưu giai đoạn n-1 ta lại có thể tiến hành tối ưu giai
đoạn n-2… cho đến khi các giai đoạn từ n giảm đến 1 được tối ưu thì coi như
hoàn thành bài toán. Gọi giá trị tối ưu của bài toán tính đến giai đoạn k là Gk,
giá trị tối ưu của bài toán tính riêng ở giai đoạn k là Tk thì Gk = Gk-1 + Tk
Bước 2: Tổ chức dữ liệu và chương trình.
Tổ chức dữ liệu sao cho đạt được các yêu cầu sau :
a.Dữ liệu được tính toán dần theo từng bước.
b.Dữ liệu được lưu trữ để giảm lượng tính toán lặp lại.
c.Kích thước miền nhớ dành cho lưu trữ dữ liệu càng nhỏ càng
tốt, kiểu dữ liệu được chọn phù hợp, nên chọn đơn giản dễ truy cập.
Cụ thể:
+ Các giá trị của Fk thường được lưu trữ trong một bảng (mảng một
chiều hoặc hai v.v..chiều).
+ Cần lưu ý khởi trị các giá trị ban đầu của bảng cho thích hợp, đó
là các kết quả của các bài toán con có kích cỡ nhỏ nhất của bài toán đang giải.
+ Dựa vào công thức, phương trình truy toán và các giá trị đã có
trong bảng để tìm dần đến các giá trị còn lại của bảng.
+ Ngoài ra còn cần mảng lưu trữ nghiệm tương ứng với giá trị tối
ưu trong từng giai đoạn.
+ Dựa vào bảng lưu trữ nghiệm và bảng giá trị tối ưu từng giai đoạn
đã xây dựng, tìm ra kết quả bài toán.
Bước 3:Làm tốt
Làm tốt thuật toán bằng cách thu gọn hệ thức và giảm kích thước miền
nhớ. Thường dùng mảng một chiều thay cho mảng hai chiều nếu giá trị một
dòng (hoặc cột) của mảng hai chiều chỉ phụ thuộc một dòng (hoặc cột) kề
trước.
Trong một số trường hợp có thể thay thế mảng hai chiều với các giá trị
phần tử chỉ nhận giá trị 0,1 bởi mảng hai chiều mới dùng kỹ thuật quản lý bit.
Trong phần một số bài toán ví dụ chúng ta sẽ nghiên cứu để hiểu rõ hơn về
quy hoạch động qua những bài toán cụ thể.
SVTH:Nhóm 6 -7
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
b) Phân tích:
Giải thuật đệ quy để tính số tổ hợp chập k của n như sau:
function TH(n,k : integer) : Integer;
begin
if (k=0) or (k=n) then TH := 1
else TH := TH(n-1, k-1) + TH(n-1,k);
end;
Gọi T(n) là thời gian để tính số tổ hợp chập k của n, thì ta có phương trình đệ
quy:
T(1) =C1 và T(n)=2T(n-1) + C2
Gpt này ta có:
T(n)=2T(n-1)+C2
=2[2T(n-2)+C2]+C2=22T(n-2)+2C2+C2
=22[2T(n-3)+C2]+2C2+C2=23T(n-3)+22C2+2C2+C2
=.........
T(n)=2kT(n-k)+C2(20+21+...+2k-2+2k-1)
=2kT(n-k)+C2(2k-1)
Quá trình trên kết thúc khi n-k=1 =>k=n-1
Khi đó T(n)=2n-1T(1)+C2(2n-1-1)=2n-1(C1+C2)-C2
=O(2n)
Vậy ĐPT=O(2n)
SVTH:Nhóm 6 -8
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
*)Nhận xét: Chỉ với 1 đa thức các bài toán con mà giải thuật trên có độ phức
tạp là hàm mũ. Điều đó chứng tỏ rằng có những bài toán con được giải lại
nhiều lần.
TH(4,2)
TH(3,1) TH(3,2)
TH(2,1) TH(2,2)
TH(2,0) TH(2,1)
……… ………
*Để khắc phục tình trạng trên ta sử dụng kỹ thuật quy hoạch động như sau:
+Phân tích bài toán: Xây dựng hàm:
Function TH(n,k: integer): integer ; { k<=n}
+Giải pháp đệ quy: TH(n,k) = TH(n-1,k-1)+ TH(n-1,k)
+Lập bảng: xây dựng 1 bảng gồm (n+1) dòng từ 0..n và (n+1) cột từ 0..n và
điền giá trị cho C(i,j) theo quy tắc tam giác pascal như sau:
C(0,0)=1
C(i,0)=1
C(i,i)=1 với 0<i<=n
C(i,j)=C(i-1,j-1)+C(i-1,j) với 0<j<i<=n)
SVTH:Nhóm 6 -9
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
j 0 1 2 3 4
i
0 1
1 1 1
2 1 2 1
3 1 3 3 1
4 1 4 6 4 1
d) -Giải thuật:
SVTH:Nhóm 6 - 10
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
e) Độ phức tạp:
Các câu lệnh gán {1},{3} và {4} tốn O(1) thời gian. Vòng lặp {5}
thực hiện i-1 lần, mỗi lần tốn O(1) thời gian. Vòng lặp {2} có i chạy từ 1 đến
n, nên nó thực hiện n lần và thời gian để thực hiện vòng lặp 2 cũng chính là
thời gian thực hiện giải thuật trên.
*Nhận xét:
+Thông qua việc xác định ĐPT ta thấy rõ rằng giải thuật quy hoạch
động(ĐPT=O(n2)) hiệu quả hơn rất nhiều so với giải thuật đệ quy
(ĐPT=O(2n).
+Tuy nhiên việc sử dụng bảng(mảng 2 chiều) như trên còn lãng phí ô
nhớ, do đó ta sẽ cải tiến thêm 1 bước bằng cách sử dụng vecto(mảng 1 chiều)
để lưu trữ kết quả trung gian.
* giải thuật:
function TH(n, k : Integer) : Integer
var V: array[0..max] of integer;
i,j,p1,p2 : integer;
begin
{1} V[0] := 1;
{2} V[1] := 1;
{3 } for i := 2 to n do
begin
{4} p1:=V[0] ;
{5} for j := 1 to i-1 do
Begin
{6} p2:=V[,j] ;
{7} V[,j]:=p1+p2;
{8} p1:=p2;
SVTH:Nhóm 6 - 11
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
end;
{9} V[i]:=1;
end;
{10} TH:= V[k] ;
End;
-ĐPT: Tương tự như trên ĐPT của giải thuật này vẫn là O(n2)
SVTH:Nhóm 6 - 12
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
writeln('c[',n,',',k,']=',c[n,k]:3);
end;
SVTH:Nhóm 6 - 13
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
write('moi ban chon:');readln(chon);
case chon of
1: th(n,k);
2: begin t:=thop(n,k);
writeln('c[',n,',',k,']=',t:3);
writeln;
end;
end;
write('ban co tiep ko?');readln(tl);
until upcase(tl)='K';
readln;
end.
2.Tìm đường đi ngắn nhất gữa mọi cặp đỉnh của đồ thị có
hướng có trọng số.
a)Bài toán:
Cho G=(V,E, W) là một đơn đồ thị có hướng có trọng số với mọi
cung(i,j), V={1,2..n} là tập các đỉnh, E là tập các các cung.Tìm đường đi ngắn
nhất gữa mọi cặp đỉnh của đồ thị .
b)Ý tưởng:
Nếu k nằm trên đường đi ngắn nhất từ i -> j thì đoạn từ i ->k và k ->j
cũng phải ngắn nhất.
Đường đi ngắn nhất giữa mọi cặp đỉnh trên đồ thị G= (V, E, W) được
biểu diễn bằng ma trận trọng số A với Aij là trọng số của cạnh (i, j).
An xn
= (aij ) nxn
Thuật toán thực hiện n bước lặp thay đổi ma trận a để cuối cùng Aij là
độ dài đường đi ngắn nhất từ vi → v j
Ở bước lặp k thì aij : vi → v j là độ dài đường đi ngắn nhất từ vi → v j không qua
mọi đỉnh lớn hơn k và ở bước lặp này ta đặt
a ij = min { aij , aik + a ki }
c)Thuật toán:
SVTH:Nhóm 6 - 14
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
Dữ liệu đầu vào: Đồ thị cho bởi ma trận trọng số a(i,j), với i, j = 1, 2,…, n
Đầu ra: :
+Ma trận đường đi ngắn nhất giữa mọi cặp đỉnh
D=[d(i,j)], trong đó d(i,j) là độ dài đường đi ngắn nhất từ i → j với mọi
cặp(i,j).
+Ma trận ghi nhận đường đi
P=[p(i,j)], trong đó P(i,j) ghi nhận đỉnh đi trước đỉnh j trong đường đi
ngắn nhất từ i đến j.
Phương pháp:
(1).Khởi tạo: +Kí hiệu D0 là ma trận xuất phát
D0=[d(i,j)]
Trong đó :
+ Ma trận P0=[p0(i,j)]
Trong đó:
+Gán k=0;
SVTH:Nhóm 6 - 15
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
Với mọi cặp (i,j), i=1..n, j=1..n ta xét nếu như đường đi từ i đến j đang có
lại dài hơn đường đi từ i tới k cộng với đường đi từ k tới j thì ta hủy bỏ đường
đi hiện thời và coi đường đi từ i đến j sẽ là nối giữa hai đường i → k và k
→ j .
Tức là nếu dk-1(i,j)>dk-1(i,k)+dk-1(k,j) thì
đặt dk(i,j):=dk-1(i,k)+dk-1(k,j) và pk(i,j):=pk-1(i,k)
Ngược lại đặt
dk(i,j):=dk-1(i,j) và pk(i,j):=pk-1(i,j)
Quay lại bước 2.
Phương pháp xác định đường đi ngắn nhất từ đỉnh i đến đỉnh j: đường đi
ngắn nhất từ i đến j gồm dãy các đỉnh
i , i1 , i2 , … , ik , ik+1 ,… , im , j.
thỏa mãn: i1 = p(i,j), i2 = p(i1,j),… , ik+1= p(kk,j), … , p(im,j) = j.
Mô tả thuật toán
Ví Dụ:
floydwar.inp Kết quả: floydwar.out
4 7 17 7 5 13
1 2 7 10 7 7 6 độ dài đường đi ngắn nhất
1 3 5 15 12 19 11 giữa mọi cặp đỉnh
2 3 7 4 1 8 7
2 4 6 2 2 3 2
3 4 11 4 4 3 4 đường đi ngắn nhất
4 1 4 4 4 4 4 giữa mọi cặp đỉnh
4 2 1 1 2 2 2
4)Mô tả
6
2 1
4
7
4
1
11
7 5
3
SVTH:Nhóm 6 - 16
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
B0:
d0 1 2 3 4 P0 1 2 3 4
1 7 5 1 2 3
2 7 6 2 3 4
3 11 3 4
4 4 1 4 1 2
d1 1 2 3 4 B1: P1 1 2 3 4
1 7 5 1 2 3
2 7 6 2 3 4
3 11 3 4
4 4 1 9 4 1 2 1
B2:
d2 1 2 3 4
1 7 5 13
2 7 6
3 11
4 4 1 8 7 P2 1 2 3 4
1 2 3 2
2 3 4
3 4
4 1 2 2 2
B3:
d3 1 2 3 4
1 7 5 13
2 7 6
3 11
4 4 1 8 7 P3 1 2 3 4
1 2 3 2
2 3 4
3 4
4 1 2 2 2
SVTH:Nhóm 6 - 17
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
B4:
d4 1 2 3 4 P4 1 2 3 4
1 17 7 5 13 1 2 2 3 2
2 10 7 7 6 2 4 4 3 4
3 15 12 19 11 3 4 4 4 4
4 4 1 8 7 4 1 2 2 2
-Căn cứ vào ma trận D ta chỉ ra khoảng cách đường đi ngắn nhất từ 4-->3,
D43=8.Tức là độ dài ngắn nhất từ 4-->3 là 8.
-Dựa vào P có thể xác định các đỉnh nằm trên đường đi ngắn nhất này.Theo P
đường đi ngắn nhất từ 4-->3 đi qua đỉnh trung gian p43=2 v à đường đi ngắn
nhất từ 2-->3 đi qua đỉnh trung gian p23=3
Vậy độ dài đường đi ngắn nhất từ 4-->3 là 8 và đường đi đó là: 4-->2-->3.
e) Cài đặt
procedure floyd;
var i,j,k:integer;
begin
f or k:=1 to n do
for i:=1 to n do
for j:=1 to n do
if (d[i,j]>d[i,k]+d[k,j]) then
begin
d[i,j]:=d[i,k]+d[k,j];
p[i,j]:=p[i,k]; {c[i,j] diem can qua}
end
else
begin
d[i,j]:=d[i,j] ;
p[i,j]:=p[i,j];
end;
end;
SVTH:Nhóm 6 - 18
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
f) Độ phức tạp
-Quy tắc cộng: Nếu T1(n) và T2(n) là thời gian thực hiện của đoạn chương
trình P1 và P2;và T1(n) = O(f(n)), T2(n) = O(g(n)) thì thời gian thực hiện của
đoạn hai chương trình đó nối tiếp nhau là T(n) = O(max(f(n),g(n))).
-Quy tắc nhân: Nếu T1(n) và T2(n) là thời gian thực hiện của đoạn chương
trình P1 và P2;và T1(n) = O(f(n)), T2(n) = O(g(n)) thì thời gian thực hiện của
đoạn hai chương trình đó lồng nhau là T(n) = O(f(n)*g(n)).
-Quy tắc tổng quát để phân tích một chương trình:
+Thời gian thực hiện của mổi lệnh gán, READ, WRITE là O(1).
+Thời gian thực hiện của một chuỗi tuần tự các lệnh được xác định bằng
quy tắc cộng. Như vậy thời gian này là thời gian thi hành một lệnh nào đó lâu
nhất trong chuỗi lệnh.
+Thời gian thực hiện cấu trúc IF là thời gian thực hiện lệnh sau THEN
hoặc sau ELSE và thời gian kiểm tra điều kiện.Thường thời gian kiểm tra điều
kiện là O(1).
+Thời gian thực hiện vòng lặp là tổng (trên tất cả các lần lặp) thời gian
thực hiện thân vòng lặp. Nếu thời gian thực hiện vòng lặp không đổi thì thời
gian thực hiện vòng lặp là tích của số lần lặp với thời gian thực hiện thân vòng
lặp.
Rõ ràng ta thấy ở chương trình có ba vòng lặp for lồng nhau nên độ phức
tạp là O( n 3 ) còn ở câu lênh if…else có độ phức tạp là O(1), nên độ phức tạp
ở đây là O( n 3 ).
Độ phức tạp là O( n 3 )
g)Chương trình DEMO
uses crt;
var d,p:array[1..100,1..100] of integer;
n,m,w:integer;
f:text;
procedure input;
var i,j,k,x,trso:integer;
SVTH:Nhóm 6 - 19
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
begin
assign(f,'floydwar.inp');reset(f);
readln(f,n,m);
for i:=1 to n do
for j:=1 to n do
begin
d[i,j]:=300;
p[i,j]:=0;
end;
for i:=1 to m do
begin
read(f,k,x,trso);
d[k,x]:=trso;
p[k,x]:=x;
end;
close(f);
end;
(*****************************************)
procedure floydwar;
var k,i,j:integer;
begin
for k:=1 to n do
for i:=1 to n do
for j:=1 to n do
if ((d[i,j])>(d[i,k]+d[k,j])) then
begin
d[i,j]:=d[i,k]+d[k,j];
p[i,j]:=p[i,k];
SVTH:Nhóm 6 - 20
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
end
else
begin
d[i,j]:=d[i,j];
p[i,j]:=p[i,j];
end;
end;
(*******************************************)
procedure output;
var i,j:integer;
begin
assign(f,'fw.out');rewrite(f);
for i:=1 to n do
begin
for j:=1 to n do
write(f,d[i,j]:10);
writeln(f);
end;
writeln(f);
for i:=1 to n do
begin
for j:=1 to n do
write(f,p[i,j]:10);
writeln(f);
end;
close(f);
end;
Begin
clrscr;
input;
floydwar;
SVTH:Nhóm 6 - 21
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
output;
write('xem ket qua trong file:fw.out');
readln;
End.
SVTH:Nhóm 6 - 22
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
F[k,V] = Max(F[k-1,V-xk*gk] + xk*vk) với xk chạy từ 0 đến V
DIV gk.
Sau khi xác định được F[k,V] thì X[k,V] là xk ứng với giá trị F[k,V]
được chọn trong công thức trên.
Để lưu các giá trị trung gian trong quá trình tính F[k,V] theo công thức
truy hồi trên, ta sử dụng một bảng gồm n dòng từ 1 đến n, dòng thứ k ứng với
đồ vật loại k và W+1 cột từ 0 đến W, cột thứ V ứng với trọng lượng V. Mỗi
cột V bao gồm hai cột nhỏ, cột bên trái lưu F[k,V], cột bên phải lưu X[k,V].
Trong lập trình ta sẽ tổ chức hai bảng tách rời là F và X.
c)Tổ chức dữ liệu cho bài toán:
Mỗi đồ vật được biểu diễn bởi một mẩu tin có các trường:
Ten: Lưu trữ tên đồ vật.
tl: Lưu trữ trọng lượng của đồ vật.
gt: Lưu trữ giá trị của đồ vật
pa: Lưu trữ số lượng đồ vật được chọn theo phương án.
Danh sách các đồ vật được biểu diễn bởi một mảng các đồ vật.
Bảng được biểu diễn bởi 1 mảng 2 chiều các số nguyên để lưu trữ các giá
trị F [k,v] và X [k,v ].
Dữ liệu đầu vào lấy từ file ‘BALO.INP’ gồm
+ Dòng thứ nhất là N và W
+ N dòng tiếp theo: dòng i+1 ghi : ten[i],tl[i] và gt[i] (i=1, 2,..., N), các
số cách nhau bởi dấu cách.
Dữ liệu sẽ được xử lí trên file và đưa kết quả ra file: ‘BALO.OUT’ có
dạng:
Ví dụ:
BALO.INP BALO.OUT
5 9 Sohieudv tendv slg tlg gtri
a 3 4 4 d 3 2 3
b 4 5 1 a 1 3 4
c 5 6 Tong tlg cac vat duoc chon:9
d 2 3 Tong gtri cac vat duoc chon:13
e 1 1
SVTH:Nhóm 6 - 23
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
*Khai báo:
const max=100;
type
dv=record
tl,gt:integer;
pa:integer;
end;
dsv=array[1..max] of dv;
bang=array[1..max,0..max]of integer;
var ds:dsv; f,x:bang;
n,w:integer;
g:text;
c)Giải thuật:
*Tạo Bảng;
procedure taobang(ds:dsv; n,w:integer; var f,x:bang);
var xk,yk,k:integer;
fmax,xmax,v:integer;
begin
for v:=0 to w do {hang dau ung voi k=1}
begin
x[1,v]:=v div ds[1].tl;
f[1,v]:=x[1,v]*ds[1].gt;
end;
for k:=2 to n do
begin
x[k,0]:=0; { ung voi v=0}
f[k,0]:=0;
for v:=1 to w do
begin
fmax:=f[k-1,v];
SVTH:Nhóm 6 - 24
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
xmax:=0; {so dv thu k dc chon}
yk:=v div ds[k].tl;
for xk:=1 to yk do
if(f[k-1,v-xk*ds[k].tl]+xk*ds[k].gt>fmax) then
begin
fmax:=f[k-1,v-xk*ds[k].tl]+xk*ds[k].gt;
xmax:=xk;
end;
f[k,v]:=fmax;
x[k,v]:=xmax;
end;
end;
end;
- Độ phức tạp tính toán: O(nw2)
*Tra bảng:
procedure trabang(var ds:dsv; n,w:integer; f,x:bang);
var k,v,ttl,tgt:integer;
begin
v:=w;
for k:=n downto 1 do
if x[k,v]>0 then
begin
ds[k].pa:=x[k,v];
v:=v-x[k,v]*ds[k].tl;
end;
end;
-Độ phức tạp tính toán: O(n)
d)Chương trình DEMO:
program vd;
const max=20;
type
SVTH:Nhóm 6 - 25
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
dv=record
tl,gt:integer;
pa:integer;
end;
dsv=array[1..max] of dv;
bang=array[1..max,0..100]of integer;
var ds:dsv; f,x:bang;
n,w:integer;
g:text;
{******KHOI TAO******}
procedure init;
var i:integer;
begin
assign(g,'BALO.INP');reset(g);
readln(g,n,w);
for i:=1 to n do
read(g,ds[i].tl,ds[i].gt);
close(g);
end;
{******TAO BANG******}
procedure taobang(ds:dsv; n,w:integer; var f,x:bang);
var xk,yk,k:integer;
fmax,xmax,v:integer;
begin
for v:=0 to w do {hang dau ung voi k=1}
begin
x[1,v]:=v div ds[1].tl;
f[1,v]:=x[1,v]*ds[1].gt;
end;
for k:=2 to n do
begin
SVTH:Nhóm 6 - 26
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
x[k,0]:=0; { ung voi v=0}
f[k,0]:=0;
for v:=1 to w do
begin
fmax:=f[k-1,v];
xmax:=0; {so dv thu k dc chon}
yk:=v div ds[k].tl;
for xk:=1 to yk do
if(f[k-1,v-xk*ds[k].tl]+xk*ds[k].gt>fmax) then
begin
fmax:=f[k-1,v-xk*ds[k].tl]+xk*ds[k].gt;
xmax:=xk;
end;
f[k,v]:=fmax;
x[k,v]:=xmax;
end;
end;
end;
{******TRA BANG******}
procedure trabang(var ds:dsv; n,w:integer; f,x:bang);
var k,v,ttl,tgt:integer;
begin
assign(g,'BALO.OUT'); rewrite(g); {tra bang roi luu ket qua vao file}
writeln(g,'do vat so luong');
ttl:=0; tgt:=0;
v:=w; {ttl:tong trong luong}
for k:=n downto 1 do {tgt:tong gia tri}
begin
if x[k,v]>0 then
begin
ds[k].pa:=x[k,v];
SVTH:Nhóm 6 - 27
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
v:=v-x[k,v]*ds[k].tl;
ttl:=ttl+ds[k].pa*ds[k].tl;
tgt:=tgt+ds[k].pa*ds[k].gt;
writeln(g,k:3,' ',ds[k].pa:3);
end;
end;
writeln(g,'tong trong lg cac vat dc chon:',ttl:4);
writeln(g,'tong gtri cac vat dc chon:',tgt:4);
close(g);
end;
{******CHUONG TRINH CHINH*******}
begin
init;
taobang(ds,n,w,f,x);
trabang(ds,n,w,f,x);
end.
4) Dãy con chung dài nhất(DCCDN) của hai dãy số.
a)Đề bài: Cho hai số nguyên dương m,n (0<m, n ≤100) và hai dãy số
nguyên: A=(a1, a2,…, am ) và B=(b1, b2,…, bn ). Tìm dãy con chung dài nhất C
nhận được từ 2 dãy A và B.
b)Một số khái niệm:
Một dãy con của một dãy là dãy ấy sau khi bỏ đi một vài phần tử, một
dãy có nhiều dãy con.
Thí dụ: C = <3,2,4> là một dãy con của A = <3,2,5,4,7> với các chỉ
số <1,2,4>.
Cho hai dãy A và B, ta nói C là dãy con chung dài nhất của A và B nếu
C là một dãy con dài nhất của cả hai dãy A và B.
Thí dụ C(3,5,3) là 1 DCCDN của A (3,2,5,4,3) và B(3,4,5,3)
*Chú ý rằng với hai dãy A, B cho trước có thể có nhiều dãy con chung
dài nhất.
SVTH:Nhóm 6 - 28
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
Cho A = ( a1,a2,...am ), ta định nghĩa tiền tố thứ i của A, với i = 1, …, m,
là Ai = ( a1,a2,..am ).
+Định lý :
Cho hai dãy số nguyên: A=(a 1, a2,…, am ), B=(b1, b2,…, bn) và
C=(c1,c2,..ck) là 1 DCCDN của A,B.Khi đó:
1. Nếu am = bn thì ck = am = bn và Ck-1 là DCCDN của Am-1 và Bn-1
2. Nếu am ≠ bn, thì ck ≠ am hàm ý C là DCCDN của Am-1 và B.
3. Nếu am ≠ bn, thì ck ≠ bn hàm ý C là DCCDN của A và Bn-1.
0 nếu i =0 hay j = 0
T[i, j] = T[i-1,j-1]+1 nếu i, j > 0 và ai = bj
SVTH:Nhóm 6 - 29
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
max(T[i, j-1],T[i-1,j]) nếu i,j >0 và ai ≠ bj
*)Giải thuật:
procedure tao_bang;
var i,j:integer;
begin
for i:=0 to m do
t[i,0]:=0;
for j:=0 to n do
t[0,j]:=0;
for i:=1 to m do
for j:=1 to n do
if a[i]=b[j] then t[i,j]:=t[i-1,j-1]+1
else
if (t[i,j-1]>t[i-1,j]) then t[i,j]:=t[i,j-1]
else
t[i,j]:=t[i-1,j];
end;
*) ĐPT: Ta dễ dàng tính được ĐPT của thủ tục này =O(m.n)
Từ bảng T, ta biết được độ dài DCCDN. Vấn đề còn lại là tìm các phần tử
của DCCDN
*Sau đây là cách tìm DCCDN :
SVTH:Nhóm 6 - 30
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
+Khởi tạo: DCCDN bằng rỗng, i = 5, j = 4 ( bắt đầu xét từ ô[5,4].
+vòng lặp :
N ếu a[i]=b[j] thì ta sẽ ghi phần tử a[i] (hoặc b[j] ) vào trước
DCCDN sau đó ta giảm i và j đi một đơn vị.
Còn không ta đi xét T[i,j]. Nếu T[i,j]=T[i-1,j] thì ta giảm i đi 1 đơn vị,
còn nếu T[i,j]=T[i,j-1] thì ta giảm j đi 1 đơn vị.
Quay lại vòng lặp cho đến khi i = j = 0.Ta thu được DCCDN.
Áp dụng đối với ví dụ trên, ta có các bước của thuật toán như sau:
Khởi tạo: i = 5, j = 4; DCCDN = θ ;
Vl1: i = 5, j = 4, a5=b4 nên DCCDN = 3, sau đó i = 4, j = 3.
Vl2: i = 4, j = 3,a4 ≠ b3,T[4,3]=T[3,3] nên i = 3, j = 3.
Vl3: i = 3, j = 3,a3=b3 nên DCCDN = 5,3 sau đó i = 2, j = 2.
Vl4: i = 2, j = 2,a2 ≠ b2,T[2,2]=T[1,2],nên i = 1, j = 2.
Vl5: i = 1, j = 2,a1 ≠ b2, T[1,2]=T[1,1] nên i = 1, j = 1.
Vl6: i = 1, j = 1, a1=b1 nên DCCDN = 3,5,3, sau đó i = 0, j = 0.
Kết thúc ta được DCCDN=3,5,3
*Giải thuật:
procedure tra_bang;
var i,j:integer;
begin
i:=m;
j:=n;
while (i>0)and(j>0) do
if a[i]=b[j] then
begin
write(a[i]:3);
dec(i); dec(j);
end
else
if t[i,j]=t[i,j-1] then dec(j)
else
SVTH:Nhóm 6 - 31
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
if t[i,j]=t[i-1,j] then dec(i);
end;
*ĐPT=O(max(m,n))
c) Tổ chức dữ liệu :
Dữ liệu đầu vào File DAYCON.INP có cấu trúc như sau:
- Dòng thứ nhất chứa spt của dãy A: m
- Dòng thứ 2 chứa cac phần tử của A: A1, A2,…, Am.
- Dòng thứ 3 chứa spt của dãy B: n
- Dòng thứ 4 chứa các phần tử của dãy B: B1, B2,…, Bn
Dữ liệu đầu ra File DAYCON.OUT có cấu trúc như sau:
Ghi ra hai dãy A, B ban đầu để tiện theo dõi kết quả của bài toán.
- Dòng tiếp theo ghi k là spt của DCCDN và k phần tử của nó.
- Dòng tiếp đó chứa chỉ số trong dãy A của k số hạng của C.
- Dòng cuối chứa chỉ số trong dãy B của k số hạng của C.
e)Chương trình chạy:
program dccdn;
const max=100;
type mang1 = array[1..max] of integer;
mang2 = array[0..max,0..max] of integer;
var
a,b : mang1; t: mang2;
m,n,dem:integer;
f : text;
pa,pb : mang1;
{********** DOC DL TU FILE ***********}
procedure init;
var i,j:integer;
begin
assign(f,'daycon.inp');reset(f);
readln(f,m);
for i:=1 to m do read(f,a[i]);
SVTH:Nhóm 6 - 32
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
readln(f);
readln(f,n);
for j:=1 to n do read(f,b[j]);
close(f);
end;
{************TAO BANG************}
procedure tao_bang;
var i,j:integer;
begin
for i:=0 to m do
t[i,0]:=0;
for j:=0 to n do
t[0,j]:=0;
for i:=1 to m do
for j:=1 to n do
if a[i]=b[j] then t[i,j]:=t[i-1,j-1]+1
else
if (t[i,j-1]>t[i-1,j]) then t[i,j]:=t[i,j-1]
else
t[i,j]:=t[i-1,j];
end;
{*****TRA BANG VA IN RA CAC PTU CUA DCCDN*****}
procedure tra_bang;
var i,j:integer;
begin
assign(f,'daycon.out'); rewrite(f);
write(f,'day A: ');
for i:=1 to m do write(f,a[i]:5);
writeln(f,' ');
write(f,'day B: ');
for j:=1 to n do write(f,b[j]:5);
SVTH:Nhóm 6 - 33
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
writeln(f,' ');
writeln(f,'dd day chung dai nhat cua 2 day:',t[m,n]);
write(f,'cac ptu cua day chung: ');
i:=m;
j:=n;
dem:=0;
while (i>=0)and(j>=0) do
if a[i]=b[j] then
begin
write(f,a[i]:3);
inc(dem);
pa[dem]:=i; { vi tri cua chung trong day A}
pb[dem]:=j; { vi tri cua chung trong day B}
dec(i); dec(j);
end
else
if t[i,j]=t[i,j-1] then dec(j)
else
if t[i,j]=t[i-1,j] then dec(i);
writeln(f);
write(f,'vtri cua chung trong day A:');
for i:= dem downto 1 do write(f,pa[i]:5); writeln(f);
write(f,'vtri cua chung trong day B:');
for i:=dem downto 1 do write(f,pb[i]:5);
close(f);
end;
{******* Chuong trinh chinh ******}
begin
init;
tao_bang;
tra_bang;
SVTH:Nhóm 6 - 34
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
end.
SVTH:Nhóm 6 - 35
Đề tài:QUY HOẠCH ĐỘNG Gvhd:Phan Đoàn Ngọc
Phương
KẾT LUẬN
Quy hoạch động (dynamic programming) giải các bài toán bằng cách kết
hợp các lời giải của các bài toán con của bài toán đang xét.
Phương pháp này khả dụng khi các bài toán con không độc lập đối với
nhau, tức là khi các bài toán con có dùng chung những bài toán “cháu”
(subsubproblem).
Cho tới 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.. Khi giải
các bài toán tối ưu, để biết được bài toán có thể giải bằng quy hoạch động hay
không, ta có thể đặ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 ?”.
SVTH:Nhóm 6 - 36