Lập công thức

Một phần của tài liệu Phương pháp quy hoạch động và một số ví dụ cụ thể (Trang 59)

n chíh là phầ tử C[, k] trog mảg

2.3Lập công thức

Dễ thấy rằng mảnh đất thứ i có ai cây oliu và dải đất thứ j có bj – 1 cây oliu. Coi các mảnh đất và các dải đất là các “đồ vật”, đồ vật thứ k có khối lượng wk (số cây bách) và vk (là số cây oliu). Nếu k là mảnh đất i thì wk = vk = ai, nếu k là dải đất thì wk = bi và vk = bj – 1. Ta cần tìm các đồ vật sao cho tổng khối lượng của chúng không vượt quá Q và tổng “ giá trị” là lớn nhất. Đây chính là bài toán cái túi trong trường hợp thứ nhất.

2.4 Thuật toán

Void inputdata () {

ifstream fi( input)

for ( int i =0; i <= m; i++) {

fi >> w[i]; v[i] = w[i]; }

for ( int i = m + 1; i <= n+m; i++) { fi >> w[i]; v[i] = w[i] – 1; } fi.close(); } Void outputdata {

Ofstream fo( output); fo << f[m+n][q]; fo.close();

}

Int max ( int a, int b) { If ( a> b) return a; Else return b; } Void process() { for ( j = 0; j <= q; j++)

for ( i = 0; i <= n+m; i++) for ( i = 1; i <= n+m; i++) for ( j = 1; j <= q; j++) {

if (w[i] <= j)

f[i][j] = max(f[i-1][j],f[j-1][j-w[i]] + v[i]; else f[i][j] = f[i-1][j] } } } 2.5 Chứng minh tính đúng đắn

• Tính đúng đắn: do f[i][j]= max(f[i-1][j], f[i-1][j-a[i]] + b[i]),tức là tại mỗi bước xét,thì giá trị f[i,j] trước đó đã được tối ưu nhất nên kết quả của bài toán sẽ là tối ưu nhất.

• Tính dừng: Trong chương trình sử dụng 2 vòng lặp chính là for i = 1 →n và for j= 1→w, mà n: số lượng đồ vật và w: khối lượng cho phép của balo là hữu hạn lên thuật toán sẽ dừng.

2.6 Độ phức tạp thuật toán

• Không gian: Thuật toán cài đặt sử dụng 1 mảng 2 chiều f và 2 mảng 1 chiều.Vậy độ phức tạp không gian là O(n2).

• Thời gian: O(n2).

2.7 Ứng dụng

Ứng dụng trong giải thuật di truyền, trong kinh doanh, toán tổ hợp, lý thuyết phức tạp tính toán, mật mã học và ứng dụng.

3 Bài toán nhân ma trận 3.1 Phát biểu bài toán

Như đã biết, tính của ma trận Aik kích thước m.n với ma trận Bkj kích thước n.p là ma trận Cij kích thước m.p với các phần tử được tính theo công thức:

1q q ij jk ki k c a b = =∑ 1 ≤ i ≤m, 1 ≤ j ≤ p.

Nhân một ma trận kích thước Am.n với một ma trận Bn.p, số phép nhân phải thực hiện là m.n.p. Mặt khác phép nhân các ma trận có tính kết hợp, tức là:

(A.B).C = A.(B.C)

Do đó khi tính tích nhiều ma trận, ta có thể thực hiện theo các trình tự khác nhau, mỗi trình tự tính sẽ quyết định số phép nhân cần thực hiện.

Cho N ma trận A1,A2…An, ma trận Ai có kích thước là di.di+1. Hãy xác định trình tự nhân ma trận A1.A2…An sao cho số phép nhân cần thực hiện là ít nhất.

• Input:

- n: số ma trận

- n+1 số lần lượt là kích thước của các ma trận theo quy tắc: kích thước của ma trận thứ I là di.di+1.

• Output: (adsbygoogle = window.adsbygoogle || []).push({});

- Trình tự nhân và số phép nhân

Ví dụ: Tính tích M = ABCD của bốn ma trận, trong đó A có kích thước

13 x 5, B có kích thước 5 x 89, C có kích thước 89 x 3 và D có kích thước 3 x 34.

• Input: n=4

D[5] = 13.5 .89.3.34

• Output:

3.2 Ý tưởng 30s

Để tìm phương pháp hiệu quả nhất, chúng ta có thể liệt kê tất cả các cách điền dấu ngoặc vào biểu thức tích ma trận đã cho và tính số lượng phép nhân đòi hỏi theo mỗi cách.

Ký hiệu T(n) là số cách điền các dấu ngoặc vào biểu thức tích của n ma trận. Giả sử ta định đặt dấu ngoặc phân tách đầu tiên vào giữa ma trận thứ i và ma trận thứ (i + 1) trong biểu thức tích, tức là:

M = (M1 M2 … Mi)(Mi+1 Mi+2 … Mn)

Khi đó có T(i) cách đặt dấu ngoặc cho thừa số thứ nhất (M1 M2 … Mi) và T(n-i) cách đặt dấu ngoặc cho thừa số thứ hai (Mi+1 Mi+2 … Mn) và từ đó T(i)T(n-i) cách tính biểu thức (M1 M2 … Mi)(Mi+1 Mi+2 … Mi). Do i có thể nhận bất cứ giá trị nào trong khoảng từ 1 đến n-1, suy ra ta có công thức truy hồi sau để tính T(n):

11 1 ( ) n ( ) ( ) i T nT i T n i = = ∑ −

Bảng dưới đây cho một số giá trị của T(n).

n 1 2 3 4 5 10 15

T(n )

1 1 2 5 14 4862 2674440

Giá trị của T(n) được gọi là số Catalan. Công thức sau đây cho phép tính T(n) qua hệ số tổ hợp: 1 2 2 1 ( ) n n T n C n − − = n ≥ 2.

Từ đó T(n) = 4nn2. Như vậy, phương pháp duyệt toàn bộ không thể sử dụng để tìm cách tính hiệu quả biểu thức tính của n ma trận, khi n lớn.

3.3 Lập hệ thức

Ta nhận thấy rằng: nếu đặt dấu ngoặc đầu tiên giữa ma trận thứ i và thứ (i+1) của biểu thức tích là tối ưu, thì cả hai tích con (M1M2 … Mi) và (Mi+1Mi+2 … Mn) cũng phải được tính một cách tối ưu. Khi đó tổng số phép nhân cần phải thực hiện sẽ bằng tổng số phép tính để nhân hai dãy con (M1M2 … Mi) và (Mi+1Mi+2 … Mn) cộng với số phép tính để nhân hai ma trận tương ứng với hai dãy con này.

Để tối ưu việc nhân dãy ma trận (M1M2 … Mn) ta quy về việc tối ưu nhân hai tích con (M1M2 … Mi) và (Mi+1Mi+2 … Mn)

Gọi mij là số phép nhân ít nhất cần thực hiện để tính tích (Mi+1Mi+2 … Mj) , 1 ≤ i ≤ j ≤ n Lời giải cần tìm sẽ là m.n

Giả sử kích thước của các ma trận được cho bởi véc tơ d[1, 2, .…, n, n+1], trong đó ma trận Mi có kích thước di.di+1, i = 1, 2, 3, … n. Ta sẽ xây dựng bảng giá trị mij lần lượt theo từng đường chéo, trong đó đường chéo thứ s chứa các phần tử mi j thoả mãn j – i = s.

 s = 0 : j – i = 0

 s = 1 : j – i = 1: tích của 2 ma trận liên tiếp  s = 2 : j – i = 2: tích của 3 ma trận liên tiếp

...

 s = n - 1: j – i = n – 1 : tích của n ma trận liên tiếp Để tính bảng giá trị mi j ta có thể sử dụng quy tắc sau đây:

s = 0; mi j = 0 i = 1, 2, …, n s = 1; mi j = di.di+1.di+2 , i = 1, 2, …, n - 1

1 < s < n; mij = min{mik + mk+1,s + di.dk+1.ds+1 : 1 ≤ k <s}, i = 1, 2, …, n – s. (adsbygoogle = window.adsbygoogle || []).push({});

Ví dụ : Tìm cách tính tối ưu cho tích của bốn ma trận ở ví dụ trên:

Ta có n = 4 ; d = (13, 5, 89, 3, 34). Với s = 1, m12 = 5785, m23 = 1335 và m34 = 9078. Với s = 2

m13 = min(m11 + m23 + 13 x 5 x 3, m12 + m33 + 13 x 89 x 3) = min(1530, 9256) = 1530 m24 = min(m22 + m34 + 5 x 89 x 34, m23 + m44 + 5 x 3 x 34) = min(24208, 1845) = 1845 Với s = 3 m14 = min(m11 + m24 + 13 x 5 x 34), {k = 1} m12 + m34 + 13 x 89 x 34, {k = 2} m13 + m44 + 13 x 3 x 34, {k = 3} = min(4055, 54201, 2856) = 2856. Bảng giá trị mij được cho trong hình vẽ dưới đây

Để tìm lời giải tối ưu, ta dùng 2 mảng truoc[] và sau[] để lưu vị trí ngoặc. Quan sát bảng mij trên, ta thấy vị trí đặt dấu ngoặc là vị trí ứng với giá trị min của từng đường chéo.

Ví dụ:

Với s = 1, min = 1335 ứng với ô m23, vậy truoc[1] = 2 và sau[1] = 3. Ta có M = A.(B.C).D

Với s = 2, min = 1530 ứng với ô m13, vậy truoc[2] = 1 và sau[2] = 3 Ta có M = (A.(B.C)).D j=1 2 3 4 i=1 0 5785 1530 2856 2 0 1335 1845 s=3 3 0 9078 s=2 4 0 s=1 s=0

3.4 Thuật toán

procedure Matrix-Chain(d,n)

{m[i,j] - chi phí tối ưu thực hiện nhân dãy Mi . . . Mj; }

begin

for i: = 1 to n do m[i,j]: = 0; //khởi tạo

for s: = 1 to n do // s = chỉ số của đường chéo for i: = 1 to n - s do begin j: = i + s - 1; m[i,j] = + ; for k: = i to j - 1 do begin q: = m[i,k] + m[k+1,j] + d[i-1]*d[k]*d[j]; if(q<m[i,j]) then begin m[i,j] = q; h[i,j] = k; end; end; end; end; 3.5 Tính đúng đắn và tính dừngTính đúng đắn:

Như đã nêu trên, để tối ưu việc nhân dãy ma trận (M1 M2 … Mn) ta quy về việc tối ưu nhân hai tích con (M1 M2 … Mi) và (Mi+1 Mi+2 … Mn).

Từ công thức :

mij = min{mik + mk+1,s + di.dk+1.ds+1 : 1 ≤ k <s}, 1 < s < n, i = 1, 2, …, n – s.

Ta thấy với mỗi tích con, số lượng các phép tính được chọn luôn là tối ưu trong số các phương án. Vậy theo quy nạp, tích dãy ma trận (M1 M2 … Mn) cũng là tối ưu.

Tính dừng:

Trong chương trình, ta có hai thao tác chính là lặp s: 1 và lặp k: 1-1. Vì n hữu hạn nên thuật toán luôn dừng.

3.6 Độ phức tạp thuật toán

Với mỗi s > 0, có n – s phần tử trên đường chéo cần tính, để tính mỗi phần tử đó ta cần so sánh s giá trị số tương ứng với các giá trị có thể của k. Từ đó suy ra số phép toán cần thực hiện theo thuật toán là cỡ

1 1 1 2 1 1 1 2 3 3 ( )s ( 1) / 2 ( 1)(2 1) / 6 ( ) / 6 0( ) n n n s s s n s n s s n n n n n n n n − − − = = = − = − = − − − − = − = ∑ ∑ ∑

Vì cần mảng 2 chiều lưu trữ giá trị mij, nên chi phí không gian là O(n2), chi phí thời gian là O(n3). Đây là bài toán có chi phí lớn nhất trong tất cả các bài toán QHĐ thường gặp.

Một phần của tài liệu Phương pháp quy hoạch động và một số ví dụ cụ thể (Trang 59)