Máy biến đổi và otomat

Một phần của tài liệu Thuật toán kiểm tra tính chất mã bằng otomat hữu hạn (Trang 37)

2.2.1. Khái niệm

Định nghĩa 2.7. Máy biến đổi trạng thái hữu hạn có trọng số T (gọi tắt là máy biến đổi) trên nửa vành  là một bộ 8 T= (Q, A, , e, I, f, , ) ở đó: Q là tập hữu hạn các trạng thái, A là bảng chữ cái vào hữu hạn,  là bảng chữ cái ra hữu hạn, E  Q × (A {} × ( {} × ×Q là tập hữu hạn các phép biến đổi, IQ

- 38 -

là tập các trạng thái ban đầu, F  Q là tập các trạng thái kết thúc, : I   là hàm trọng số đầu, : F là hàm trọng số kết thúc.

Cho phép biến đổi (cung) e = (q1, a, b,wg, q2)  E. Ta nói rằng e rời q1 và

đến q2, trạng thái q1 gọi là trạng thái đầu của e ký hiệu là p[e], q2 gọi là trạng

thái cuối của e ký hiệu là n[e], a là nhãn vào của e ký hiệu là i[e], wg là trọng số

của e ký hiệu là wg[e], b là nhãn ra của e ký hiệu là o[e]. Cho trạng thái qQ, ta

ký hiệu E[q] là tập các phép biến đổi rời q.

Cho  = e1…ek E*, ở đó n[ei-1] = p[ei], i = 2,…, k và p[e1] = q, n[ek] = q

đƣợc gọi là đường đi từ q đến q. Ta mở rộng hàm trạng thái đầu p, hàm trạng thái cuối n, hàm nhãn vào i, hàm nhãn ra o và hàm trọng số wg cho đƣờng đi 

nhƣ sau: n[] = n[ek] và p[] = p[e1]; nhãn vào, ra của đƣờng đi  là tích ghép nhãn vào, ra tƣơng ứng của các phép biến đổi thành phần; trọng số của đƣờng đi  là -tích trọng số của các phép biến đổi thành phần (hay i[] = i[e1]…i[ek],

o[] = o[e1]…o[ek] và wg[] = wg[e1]…wg[ek]).

Đường đi thành công trên máy biến đổi T là một đƣờng đi từ trạng thái ban đầu đến trạng thái kết thúc. Đƣờng đi  gọi là chu trình nếu n[] = p[].

Kí hiệu P(q, q) là tập các đƣờng đi từ q đến q, P(q, x, q) là tập các đƣờng đi từ q đến q với nhãn vào xA*, P(q, x, y,q) là tập các đƣờng đi từ q đến q với nhãn vào xA* và nhãn ra y*

. Ký hiệu này có thể mở rộng với tập R,R  Q

nhƣ sau:

P(R, x, R) =q R, qRP(q, x, q), P(R, x, y, R) = qR, qRP(q, x, y, q).

Máy biến đổi T là chính quy nếu với mọi xA*, y* : T (x, y) = ) , , , (IxyF P    (p[]) wg[](n[]).

- 39 -

là xác định trong . Ta có T (x, y) = 0 khi P(I, x, y, F) = . Giả sử rằng, tất cả các máy biến đổi xem xét trong luận văn đều là chính quy.

Ngoài máy biến đổi đã xem xét, dƣới đây ta xem xét một số dạng otomat sẽ đƣợc sử dụng trong luận văn.

Otomat có trọng số trên nửa vành  là bộ 7  = (Q, A, E, I, F, , ), ở đó

Q, A, I, F, ,  xác định nhƣ trong Định nghĩa 2.7 và E đƣợc xác định nhƣ sau:

E  Q × (A{}) ×  × Q.

Otomat có trọng số  là chính quy nếu với mọi x  A*: (x) = ) , , (I xF P    (p[]) wg[](n[]) là xác định trong . Ta có (x) = 0 khi P(I, x, F) = .

Otomat hữu hạn là một bộ 5  = (Q, A, E, I, F), ở đó Q, A, I, F xác định

nhƣ trong Định nghĩa 2.7, E là tập các cung rời trạng thái thuộc Q và đến trạng thái thuộc Q đƣợc gán nhãn là ký tự thuộc A  {}. Otomat hữu hạn  gọi là

otomat đa định nếu E  Q × (A  {}. Otomat hữu hạn  gọi là Otomat đơn định nếu  có duy nhất một trạng thái ban đầu và với mỗi qQ, với mỗi aA có

nhiều nhất một cung rời q với nhãn a.

Cho cung e = (p,, q)  E. Nếu p  q thì gọi e là cung rỗng, nếu p = q thì

gọi e là khuyên rỗng.

Cho đƣờng đi  = e1…ekE*, với e1 = (p0,a1,p1), e2 = (p1, a2, p2),…, ek = (pk- 1, ak, pk). Từ w = a1a2…ak gọi là nhãn của đƣờng đi , tập hợp tất cả các nhãn của các đƣờng đi thành công trong otomat hữu hạn  gọi là ngôn ngữ đƣợc đoán nhận bởi , ký hiệu là L().

Một trạng thái qQ gọi là đạt được nếu tồn tại đƣờng đi từ một trạng thái

- 40 -

đến một trạng thái kết thúc. Otomat hữu hạn  gọi là thu gọn nếu tất cả các trạng thái của  là đạt đƣợc và cũng là đối đạt đƣợc. Thuật toán kinh điển xây dựng otomat hữu hạn thu gọn đƣợc thực hiện bởi hàm ký hiệu là TRIM(), có độ phức tạp thời gian là (Q+E) và L() = L(TRIM()).

Otomat Büchi là một bộ 5  = (Q, A, E, I, F), ở đó: Q là tập hữu hạn các

trạng thái, A là bảng chữ cái, E Q × (A  {} × Q là tập hữu hạn các cung,

IQ là tập các trạng thái ban đầu, F  Q là tập các trạng thái kết thúc. Một mạch  của otomat Büchi là một dãy các trạng thái: q0, q1, q2, …, sao cho: q0I, (qi, ui,

qi+1)  E, i  0. Từ vô hạn phía phải w = u0u1…un…, với ui  A, i  0 gọi là từ của mạch . Cho tập infi() = {qQq xuất hiện vô hạn lần trên }. Mạch 

gọi là đƣợc đoán nhận bởi otomat Büchi nếu infi()  F . Tập tất cả các từ của các mạch đƣợc đoán nhận bởi otomat Büchi gọi là ngôn ngữ đoán nhận bởi otomat Büchi.

2.2.2. Hợp thành của hai máy biến đổi

Phép hợp thành là phép toán cơ bản trên máy biến đổi đƣợc sử dụng trong

nhiều ứng dụng. Cho 1, 2 là hai máy biến đổi trên nửa vành giao hoán , có bảng chữ cái vào của 2 trùng khớp bảng chữ cái ra của 1. Khi đó, hợp thành của 1 và 2 là máy biến đổi ký hiệu là 12 xác định với tất cả x, y nhƣ sau [15, 16]:

(12)(x, y) =

z

1(x, z) 2(z, y).

Tồn tại một thuật toán tổng quát và hiệu quả thực hiện phép hợp thành của hai máy biến đổi 1 và 2[15, 16], trạng thái của 12 là cặp trạng thái của 1 và 2, phép biến đổi của 12 xác định theo quy tắc sau:

(q1, a, b,wg1, q2) và (q1, b, c,wg2, q2)  ((q1, q1), a, c,wg1wg2,(q2, q1)) Thuật toán 2.1 thực hiện phép hợp thành của hai máy biến đổi.

- 41 -

Input: 1, 2 là hai máy biến đổi.

Output: Máy biến đổi 12.

//ENQUEUE, DEQUEUE là phép bổ sung và loại bỏ phần tử trên hàng đợi S.

Các bƣớc thực hiện 1. Q I1× I2; S  I1× I2; 2. while S  do 3. (q1, q2)  DEQUEUE(S); 4. if (q1, q2)  I1× I2 then II {(q1, q2)}; (q1, q2) 1(q1) 2(q2); 5. if (q1, q2) F1×F2 then F F {(q1, q2)}; (q1, q2)  1(q1) 2 (q2); 6. for each (e1, e2) in E[q1] ×E[q2] such that o[e1] = i[e2] do

if (n[e1], n[e2]) Q then

QQ{(n[e1],n[e2])}; ENQUEUE(S,(n[e1], n[e2]));

E E{((q1, q2), i[e1], o[e2], wg[e1]  wg[e2], (n[e1], n[e2]))}; 7. Return 12;

Độ phức tạp thời gian của thuật toán ((Q1 + E1)(Q2+E2)) [15, 16]. Ta có thể áp dụng Thuật toán 2.1 trên otomat có trọng số, otomat hữu hạn hay otomat Büchi. Khi đó, ta coi nhãn vào và nhãn ra của mỗi cung là trùng nhau, trọng số của các phép biến đổi bằng 0 với trƣờng hợp otomat hữu hạn hay otomat Büchi.

Ví dụ 2.17. Cho otomat hữu hạn  = (A, Q1, I1, F1, E1) (Hình 2.2.a), ở đó:

- 42 -

E1 = {(0, b, 1), (0, a, 2), (1, a, 1), (1, c, 3), (2, b, 3)}

Hình 2.2. Hợp thành của otomat với máy biến đổi trên nữa vành Tropical

Cho máy biến đổi  = (A, , Q2, I2, F2, E2, , ), ở đó:

A =  = {a, b, c}, Q2 = {0, 1, 2}, I2 = {0}, F2 = {2},

E2 = {(0, b, c, 0.3, 1), (1, a, b, 0.4, 2), (2, ɛ, b, 0.6, 2), (2, c, b, 0.2, 2)},

:{0} {0.0}, :{2}{0.7}.

Áp dụng Thuật toán 2.1 ta nhận đƣợc máy biến đổi = (A, , Q, I, F, E, , ), ở đó: A =  = {a, b, c}; Q = {v0 = (0,0), v1 = (1, 1), v2 = (1, 2), v3 = (3, 2)}; a 0 1 2 0 3 c b a b (a) 0 b:c/0.3 1 a:b/0.4 ɛ:b/0.6 2/0.7 c:b/0.2 (b) b:c/0.3 a:b/0.4 ɛ:b/0.6 (3,2)/0.7 (c) ɛ:b/0.6 c:b/0.2 (0,0) (1,1) (1,2)

- 43 -

I= {v0}; F = {v3};

E= {(v0, b, c, 0.3, v1), (v1, a, b, 0.4, v2), (v2, ɛ, b, 0.6, v2), (v2, c, b, 0.2, v3), (v3, ɛ, b, 0.6, v3)};

:{v0}{0.0}; :{v3}{0.7}.

2.2.3. Lƣỡng cực hoá, mở rộng kiểu 2 và kiểu 3 của otomat

Cho otomat hữu hạn  = (Q, A, E, I, F) đoán nhận ngôn ngữ X A+.

Lưỡng cực hoá  (xem [1] là otomat hữu hạn 1 = (Q1, A, E1, I1, F1), ở đó:

i) Q1 = Q {s, f}, s, f  Q và s f; I1 = {s}, F1 = {f}.

ii) E1 = E {(s, a, q)  (p, a, q) E, p  I} với

E = E {(p, a, f)  (p, a, q)  E, q F}.

Otomat hữu hạn 1 có duy nhất một trạng thái ban đầu, một trạng thái kết thúc, trạng thái ban đầu và trạng thái kết thúc không trùng nhau, không có cung đến trạng thái ban đầu và không có cung rời trạng thái kết thúc.

Ta thấy 1 chỉ có một trạng thái ban đầu và một trạng thái kết thúc, để đơn giản ta ký hiệu 1 = (Q1, A, E1, s, f) và gọi s (trạng thái ban đầu) là cực vào, f (trạng thái kết thúc) là cực ra. Thuật toán lƣỡng cực hoá otomat hữu hạn  thực hiện bởi hàm ký hiệu BA(), có độ phức tạp thời gian (Q+E).

Cho otomat hữu hạn 1 = BA(), đoán nhận ngôn ngữ X = (1)  A+.

Mở rộng kiểu 2 của 1 là otomat 2 đoán nhận (còn gọi là mở rộng kiểu Büchi), bằng cách bổ sung một cung rỗng đi từ cực ra tới cực vào của 1. Thuật toán mở rộng kiểu 2 của 1 thực hiện bởi hàm ký hiệu EAT2(1).

Cho otomat 2 = EAT2(BA())=(Q2, A, E2, s2, f2) đoán nhận ngôn ngữ Xω.

Mở rộng kiểu 3 (phép đảo ngƣợc) của 2 là otomat 3 = (Q3, A, E3, s3, f3) xác định nhƣ sau: Q3 = Q2, s3 = f2, f3 = s2, E3 là các cung đảo ngƣợc của E2. Otomat 3 đoán nhận ngôn ngữ L. Thuật toán mở rộng kiểu 3 của 2 thực hiện bởi hàm ký hiệu là EAT3(2), với độ phức tạp thì gian là (Q+E).

- 44 -

Nhận xét 2.2. Cho otomat hữu hạn  = (Q, A, E, I, F), c = A là hằng số.

i) Nếu 1 = BA() thì() = (1).

ii) Trƣờng hợp  là đơn định: với mỗi đỉnh pQ có tối đa c cung ra, vậy số

cung tối đa của  là Qc. Khi đó, thuật toán lƣỡng cực hoá otomat có độ phức

tạp thời gian (Q). Số trạng thái của BA(), EAT2(BA()) không quá Q+2, do đó có cơ sở (Q). Số cung của BA() không quá 2E+2c = 2Qc+2c, của

EAT2(BA() không quá 2Qc+2c+1, do đó cũng có cỡ (Q).

2.2.4. Tích otomat

Phép tích otomat là trƣờng hợp riêng của phép hợp thành của hai máy biến đổi. Tuy nhiên, để cho đơn giản trong ứng dụng, ta trình bày phép tích otomat đối với các otomat đƣợc đề cập trong chƣơng 3. Cho hai otomat 1 = (Q1, A, E1,

s1, f1) và 2 = (Q2, A, E2, s2, f2). Tích 1 với 2 là otomat ký hiệu PROD(1, 2) = (Q, A, E, (s1, s2), (f1, f2)). Ta xét quy tắc:

(q1, a, p1)  E1, (q2, a, p2)  E2, a  A {ɛ}

 e = ((q1, q2), a, (p1, p2))  E. (2.4) Để xác định tập Q và E của PROD(1, 2) ta thực hiện nhƣ sau:

i) Bổ sung (s1, s2) vào Q.

ii) Với mỗi trạng thái (q1, q2) đã đƣợc bổ sung vào Q, theo quy tắc (2.4) ta bổ sung cung e vào E, nếu n[e] = (p1, p2) Q thì ta bổ sung (p1, p2) vào Q.

iii) Lặp lại bƣớc ii) với các trạng thái bổ sung vào Q.

Thuật toán 2.2 dƣới đây thực hiện tích hai otomat.

Thuật toán 2.2. PROD (1,2)

Input: 1 = (Q1, A, E1, s1, f1), 2 = (Q2, A, E2, s2, f2).

Output:  = (Q, A, E, s, f) là tích của 1 và 2.

- 45 - s  (s1, s2); f  (f1, f2); E ; 2. while S  do (q1, q2)  DEQUEUE (S); 3. for each (e1, e2) in E[q1] × E[q2] do 4. if l[e1] = l[e2] then

if (n[e1], n[e2])  Q then

Q  Q  {(n[e1], n[e2])}; ENQUEUE (S, (n[e1], n[e2]));

E E  {((q1, q2), l[e1], (n[e1], n[e2]))}; 5. Return ;

Ví dụ 2.18. Cho otomat 1 = (Q1, A, E1, s1, f1) nhƣ trong Hình 2.3.a và otomat 2=(Q2, A, E2, s2, f2) nhƣ trong Hình 2.3.b. Hình 2.3.c là otomat PROD(1, 2).

Hình 2.3. Tích hai otomat s1 P1 f1 ɛ b a b (a) f2 q1 s2 q2 ɛ b a b (b) b a ɛ b a (c) b a (s1, s2) (f1, q2) b ɛ (s 1, q2) (p1, q2) (f1, f2)

- 46 -

Nhận xét 2.3.

i) Tƣơng tự nhƣ trong 2.2.2, Thuật toán 2.2 có độ phức tạp thời gian là

((Q1+E1)(Q2+E2). Theo Nhận xét 2.2, nếu 1, 2 là đơn định thì Thuật toán 2.2 có độ phức tạp thời gian là (Q1Q2).

ii) Cho otomat2= (Q2, A, E2, s2, f2) = EAT2(BA()) đoán nhận . Trên otomat PROD(2, 2), nhãn của đƣờng đi giữa hai trạng thái kế tiếp cùng dạng (f2, qi) và (f2, qj) (hoặc (pi, f2) và (pj, f2), (s2, qi) và (f2, qj), hoặc (pi, s2) và (pj, f2) là từ thuộc X (xem thêm Ví dụ 2.19).

Ví dụ 2.19. Cho otomat 2 = (Q2, A, E2, s2, f2) = EAT2(BA()) (Hình 2.3.a), với

X = () = {bb, ab, b}. Hình 2.3.b là otomat PROD(2, 2). Theo Nhận xét 2.3, một đƣờng đi trên PROD(2, 2) (Hình 2.3.c), ta có nhãn giữa hai trạng thái kế tiếp cùng dạng (s2, s2) và (f2, p1) là b  X, giữa (f2, p1) và (f2,f2) là bb  X, giữa (p1, f2) và (f2, f2) là b  X, giữa (s2, s2) và (f2, f2) là ab  X. ɛ b b b (a) p1 s1 f2 a ɛ b b (b) (p1, f2) (s2,s2) (f2, f2) a (p1, s2) ɛ (f2, p1) (s1, s2) b b b ɛ b (p1, p1) b b b

Hình 2.4. Nhãn của đường đi giữa hai trạng thái kế tiếp cùng dạng

b ɛ

(c)

(s2, s2) (f2, p1) (s2, p1) b (p1, f2) ɛ (p1, s2) b (f

- 47 -

2.2.5. Tích hợp otomat

Cho hai otomat 1 = (Q1, A, E1, s1, f1), 2 = (Q2, A, E2, s2, f2). Tích hợp của 1 và 2 là otomat ký hiệu PRODUNI(1, 2) = (Q, A, E, I, {(f1, f2}), ở đó

I = {(f1, q) q  Q2, q  f2, q  s2}, tập Q và E đƣợc xác định theo các bƣớc thực hiện nhƣ sau:

i) Bổ sung các trạng thái của I và Q.

ii) Với mỗi trạng thái (q1, q2) đã đƣợc bổ sung vào Q, theo quy tắc (2.4) ta bổ sung e vào E, nếu n[e] = (p1, p2) Q.

iii) Lặp lại bƣớc ii) với các trạng thái bổ sung vào Q.

Để đơn giản trong ứng dụng, ta đƣa PRODUNI(1, 2) về dạng có một trạng thái ban đầu, bằng cách bổ sung vào Q trạng thái ban đầu (s, s) chƣa có

trong Q và các cung rỗng từ (s, s) tới các trạng thái trong I. Khi đó ta có

PRODUNI(1, 2) = (Q, A, E, (s, s), (f1, f2)).

Ví dụ 2.20. Cho otomat 1 = (Q1, A, E1, s1, f1) nhƣ trong Hình 2.3.a và otomat 2 = (Q2, A, E2, s2, f2) nhƣ trong Hình 2.3.b. Hình 2.5 là otomat PRODUNI(1,2) Nhận xét 2.4. Hình 2.5. Tích hợp hai otomat ɛ b (f1, q2) (s, s) ɛ (f1,q1) ɛ (s1, q1) b (f 1, f2) (s1, q2) (p1, q1) (s1, s2) ɛ a a b

- 48 -

i) Nhƣ trong mục 2.2.5, thuật toán xây dựng PRODUNI(1,2) có độ phức tạp thời gian là (Q1+E1)(Q2+E2)). Theo nhận xét 3.1, nếu 1, 2 là đơn định thì thuật toán này có độ phức tạp thời gian là (Q1Q2).

ii) Cho otomat2 = (Q2, A, E2, s2, f2) = EAT2(BA()) đoán nhận , trên otomat PRODUNI(1,2), nhãn của đƣờng đi giữa hai trạng thái kế tiếp cùng dạng (f2, qi) và (f2, qj) (hoặc pi, f2) và (pj, f2)) là từ thuộc X.

2.2.6. Sự tồn tại đƣờng đi kiểu 1 và kiểu 2

Cho đồ thị hữu hạn có hƣớng G = (V, E) với hai đỉnh đặc biệt là đỉnh khởi

đầu s và đỉnh kết thúc f (s f). Trên G có cặp (U, D), với U  V gọi là tập đỉnh

khoá trên, D  V gọi là tập đỉnh khoá dưới, U  D =  và s, f  U  D. Cho đƣờng đi  gồm dãy các đỉnh v1,v2,…,vk (với s = v1) trên G.

i) Nếu có1<i<j<k sao cho v1U, vjD, vk= vi thì  gọi là đƣờng đi kiểu 1.

ii) Nếu có 1<i<k sao cho v1U, vk = f thì  gọi là đƣờng đi kiểu 2.

Bài toán 2.1. Cho đồ thị hữu hạn có hƣớng G = (V, E) nhƣ ở trên. Cho biết trên

G có tồn tại đƣờng đi kiểu 1 hoặc kiểu 2 hay không?

Để xác định sự tồn tại của đƣờng đi kiểu 1 hoặc kiểu 2 trên G, ta xây dựng đồ thị G = (V, E) bằng kỹ thuật sao chép đồ thị từ đồ thị G nhƣ sau:

i) Với vV sao chép thành ba đỉnh (v,1), (v,2) và (v,3) của V.

ii) Với (u,v)  E:

+ Sao chép thành ba cung ((u,1),(v,1)),((u, 2),(v, 2)),((u, 3),(v, 3)) của E. + Nếu u  U thì bổ sung vào E cung ((u,1), (v, 2)).

+ Nếu u  D thì bổ sung vào E cung ((u, 2), (v, 3)).

Nhận xét 2.5. Với G ta có V = 3V, E  5E. Tập các đỉnh dạng (v, k) cảm sinh trong G của đồ thị Gk, k =1,2, 3. Mỗi đồ thị con Gk đều đẳng cấu với G, G

- 49 -

thực chất là sự kết nối có chọn lọc của ba đồ thị con G1, G2, G3, chỉ có các cung đi từ G1 đến G2 và từ G2 đến G3 mà không có cung chiều ngƣợc lại.

Thuật toán 2.3 dƣới đây thực hiện xây dựng đồ thị G từ đồ thị G:

Thuật toán 2.3. XCOPY3(G)

Input: Đồ thị hữu hạn có hƣớng G.

Output: Đồ thị G là đồ thị sao chép từ G.

// Thuật toán dùng mảng: upkey[q] = 1  q  U; downkey[q] = 1  q  D.

1. V; E;

2. For each u in V do VV {(u,1), (u,2), (u,3)}; 3. For each u in V do

4. For each v in Next(u) do

EE {((u,1), (v,1), (u,2), (v,2), (u,3), (v,3))}; if upkey[u] = 1 then EE {((u,1), (v,2))}; if downkey[u] = 1 then EE {((u,2), (v,3))}; 5. Return G;

Hiển nhiên, Thuật toán XCOPY3 có độ phức tạp thời gian (V+E). Ý nghĩa của đồ thị G đƣợc thể hiện bởi Định lý 2.3 dƣới đây.

Định lý 2.3.(xem [4, tr. 63]) Cho đồ thị hữu hạn có hướng G = (V, E), có đỉnh

khởi đầu sV, đỉnh kết thúc fV (s f), với cặp (U, D) mà tập đỉnh khoá trên là

U  V, tập đỉnh khoá dưới là DV, UD =  (s, f  UD) và G= XCOPY3(G).

i) Trên G tồn tại đường đi kiểu 1 khi và chỉ khi trên Gtồn tại đường đi từ đỉnh (s,1) đến đỉnh (v,3), ở đó v  U và (v,1) thuộc .

ii) Trên G tồn tại đường đi kiểu 2 khi và chỉ khi trên G tồn tại đường đi từ đỉnh (s,1) đến đỉnh (f,2).

- 50 -

Để xác định sự tồn tại đƣờng đi kiểu 1, chúng ta thực hiện tô màu các đỉnh trên G. Ở đó, mỗi đỉnh có thuộc tính mark cho biết đỉnh đó đƣợc tô màu gì,

chúng ta sử dụng 4 màu nhƣ sau:

+ Đỉnh (u, i) đƣợc tô màu WHITE (hay mark[(u, i)] = WHITE) cho biết đỉnh (u, i) chƣa đƣợc “thăm”

Một phần của tài liệu Thuật toán kiểm tra tính chất mã bằng otomat hữu hạn (Trang 37)

Tải bản đầy đủ (PDF)

(75 trang)