1. Trang chủ
  2. » Luận Văn - Báo Cáo

Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế

74 1,3K 3

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 74
Dung lượng 2,07 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Đồ thị cũng được dùng để giải nhiều bài toán thuộc những lĩnh vực rất khác nhau như: người ta có thể dùng đồ thị để biểu diễn sự cạnh tranh các loài trong môi trường sinh thái, dùng đồ t

Trang 1

MỤC LỤC

Lời mở đầu………

Chương 1: Cơ sở lý thuyết ………

1.1 Một số khái niệm cơ bản ………

1.1.1 Khái niệm đồ thị ………

1.1.2 Các loại đồ thị ………

1.1.3 Biểu diễn đồ thị………

1.2 đồ thị hai phía

1.2.1 Định nghĩa

1.2.2 ứng dụng………

Chuơng 2: bài toán tìm bộ ghép cực đại trên đồ thị và các thuật toán ………

2.1 bài toán tìm bộ ghép cực đại trên đồ thị hai phía………

2.1.1 Bài toán ghép đôi không trọng và các khái niệm ………

2.1.2 Thuật toán đường mở ………

2.2 Bài toán tìm bộ ghép cực đại với tổng trọng số cực đại hoặc cực tiểu trên đồ thị hai phía …

2.2.1 Bài toán phân công ……….………

2.2.2 Thuật toán tìm cặp ghép với tổng trọng số trên các cạnh là lớn nhất hoặc nhỏ nhất ………

2.2.3 Thuật toán Hung-ga-ri ………

2.2.4 Phương pháp đối ngẫu Kuhn-Munkres …………

2.2.5 Nâng cấp

2.3 bài toán tìm bộ ghép cực đại trên đồ thị tổng quát

2.3.1 Các khái niệm………

2.3.2 Thuật toán Edmonds ………

2.3.3 Thuật toán Lawler ………

Chương 3: Giới thiệu ngôn ngữ delphi ………

6

8

8

8

8

8

10

10

10

11

11

11

12

12

12

13

14

16

18

20

20

21

24

27

Trang 2

3.1 Khái quát về ngôn ngữ Delphi ………

3.1.1 Delphi là gì?

3.1.2 Cấu trúc chương trình Delphi và Unit………

3.2 Form và các thành phần giao diện………

3.2.1 Xây dựng ứng dụng từ những thành phần công cụ VCL… 3.2.2 Form………

3.2.3 Các thành phần điều khiển của Windows………

3.3 Ngôn ngữ Object Pascal………

3.3.1 Các kiểu dữ liệu đơn giản………

3.3.2 Các kiểu dữ liệu có cấu trúc ………

3.3.3 Các câu lệnh cấu trúc………

3.4 Lập trình ứng dụng cơ sở dữ liệu………

3.4.1 Các cách kết nối với cơ sở dữ liệu………

3.4.2 Hạt nhân BDE………

3.4.3 Giới thiệu thành phần VCL Component dùng phát triển ứng dụng cơ sở dữ liệu………

3.4.4 Sử dụng và truy vấn bảng dữ liệu………

Chương 4: các bài toán ứng dụng ………

4.1 Bài toán điều hành Taxi………

4.1.1 Phát biểu bài toán ………

4.1.2 Phân tích bài toán

4.1.3 Chương trình

4 2 Bài toán xếp lớp học theo học chế tín chỉ………

4.2.1 Tìm hiểu về mô hình đào tạo theo học chế tín chỉ

4.2.2 Phát biểu bài toán

4.2.3 Phân tích bài toán………

4 2.4 Chương trình

27

27

29

30

30

31

32

36

36

38

39

41

41

43

43

44

46

46

46

46

49

62

62

62

63

66

Trang 3

KÕt luËn Tµi liÖu tham kh¶o ………

75

76

Trang 4

Lời mở đầu

Lý thuyết đồ thị là ngành khoa học được phát triển từ rất lâu nhưng lại có nhiều ứng dụng hiện đại Những ý tưởng cơ bản của lý thuyết đồ thị được nhà toán học Thuỵ Sỹ tên là Leonhard Euler đưa ra từ thế kỷ 18 Ông đã dùng lý thuyết đồ thị để giải quyết bài toán cầu Konigsberg nổi tiếng

Đồ thị cũng được dùng để giải nhiều bài toán thuộc những lĩnh vực rất khác nhau như: người ta có thể dùng đồ thị để biểu diễn sự cạnh tranh các loài trong môi trường sinh thái, dùng đồ thị ai có ảnh hưởng lên ai trong một tổ chức nào đó và cũng có thể dùng đồ thị để biểu diễn các kết cục của cuộc thi đấu thể thao, hay cũng có thể dùng đồ thị để giải các bài toán như bài toán tính số các tổ hợp khác nhau của các chuyến xe giữa hai thành phố trong một mạng giao thông, bài toán đi tham quan tất cả các phố của một thành phố sao cho mỗi phố đi qua

đúng một lần, hay bài toán tìm số các màu cần thiết để tô các vùng khác nhau của một bản đồ Đồ thị với các trọng số được gán cho các cạnh của nó có thể dùng

để giải các bài toán như bài toán tìm đường đi ngắn nhất giữa hai thành phố trong một mạng giao thông, bài toán phân công lao động sao cho tổng lợi nhuận thu

được là lớn nhất

Chính vì đồ thị có thể được sử dụng để giải quyết nhiều bài toán thuộc nhiều lĩnh vực khác nhau một cách dễ dàng và phổ biến như vậy nên đồ thị nắm giữ một vai trò hết sức quan trọng trong cuộc sống, đặc biệt là trong lĩnh vực Công nghệ Thông tin, dựa vào đồ thị và các thuật toán trên đồ thị người ta có thể xây dựng nên các phần mềm hữu ích phục vụ cho các lĩnh vực khác có được kết quả bài toán cần giải quyết một cách nhanh chóng và chính xác

Hiểu được tầm quan trọng của đồ thị trong ngành học mà mình theo đuổi

và say mê, được sự quan tâm, tận tình chỉ bảo, động viên của cô giáo Ths

Trương Hà Hải, em đã chọn nghiên cứu đề tài ứng dụng lý thuyết đồ thị giải

một số bài toán trong thực tế với mong muốn sau khi hoàn thành đề tài này em

sẽ khám phá được nhiều hơn các ứng dụng của đồ thị trong thực tế và một số thuật toán đặc biệt hiệu quả ứng dụng trên đồ thị để giải quyết các bài toán phục

vụ nhu cầu thực tế

Trang 5

Em xin gửi lời cảm ơn chân thành tới cô giáo Ths Trương Hà Hải cùng

các thầy giáo, cô giáo khác đã tận tình chỉ bảo để em hoàn thành đề tài này Em cũng xin gửi lời cảm ơn tới các bạn sinh viên lớp K1B đã có những ý kiến đóng góp để chương trình của em được hoàn thiện hơn

Mặc dù đã hết sức cố gắng nhưng chắc chắn đề tài của em không tránh khỏi những thiếu sót Em rất mong nhận được sự góp ý của các thầy cô giáo và các bạn để đề tài của em được hoàn thiện hơn

Em xin chân thành cảm ơn !

Trang 6

Chương 1 Cơ sở lý thuyết 1.1 Một số khái niệm cơ bản

1.1.1 Khái niệm đồ thị

Đồ thị là một cấu trúc rời rạc gồm các đỉnh và các cạnh nối các đỉnh đó

Đồ thị được ký hiệu là G = (V, E), trong đó V là tập đỉnh và E là tập cạnh

Trang 7

b Ma trận liền kề

Giả sử G = (V, E) là một đồ thị đơn trong đó |V| = n và các đỉnh được liệt

kê tuỳ ý v1, , vn Ma trận liền kề A của G ứng với danh sách các đỉnh này là ma

trận không – một cấp n*n có phần tử hàng i, cột j bằng 1 nếu vi và vj liền kề nhau,

và bằng 0 nếu chúng không được nối với nhau

c Ma trận liên thuộc

Giả sử G = (V, E) là một đồ thị vô hướng, v1, v2, , vn là tập các đỉnh còn

e1, e2, , em là tập các cạnh của nó Khi đó ma trận liên thuộc theo thứ tự trên của

V và E là ma trận M = [mij] trong đó:

mij = 1 nếu cạnh ej nối với đỉnh vi

mij = 0 nếu cạnh ej không nối với đỉnh vi

Trang 8

Một đơn đồ thị vô hướng G = (V, E) được gọi là đồ thị hai phía nếu tập các

đỉnh V có thể phân thành hai tập con không rỗng, rời nhau X và Y sao cho mỗi

cạnh của đồ thị nối một đỉnh của X với một đỉnh của Y

Khi đó, người ta còn ký hiệu G là ( X U Y, E) và gọi một tập (giả sử là tập

X) là tập các đỉnh trái và tập còn lại là tập các đỉnh phải của đồ thị hai phía G

Các đỉnh thuộc X còn gọi là các X_đỉnh, các đỉnh thuộc Y gọi là các Y_đỉnh

Trang 9

Chương 2 Bài toán tìm bộ ghép cực đại trên đồ thị

Và các thuật toán 2.1 bài toán tìm bộ ghép cực đại trên đồ thị hai phía

2.1.1 Bài toán ghép đôi không trọng và các khái niệm

Cho một đồ thị hai phía G = ( X U Y, E) ở đây X là tập các đỉnh trái và Y

là tập các đỉnh phải của G X = { x[1], x[2], , x[m] }, Y = { y[1], y[2], , y[n] }

Một bộ ghép của G là tập hợp các cạnh của G đôi một không có đỉnh chung Bài toán ghép đôi là tìm một bộ ghép lớn nhất (nghĩa là có số cạnh lớn nhất) của G

đường mở

Một cách dễ hiểu, có thể quan niệm như sau:

Ě Một đường pha là một đường đi đơn trong G bắt đầu bằng một X_đỉnh là đỉnh

nhạt, đi theo một cạnh nhạt sang Y rồi đến một cạnh đậm về X, rồi lại đến một cạnh nhạt sang Y cứ xen kẽ nhau như vậy

Ě Một đường mở là một đường pha Bắt đầu từ một X_đỉnh là đỉnh nhạt kết thúc bằng một Y_đỉnh là đỉnh nhạt

Ví dụ: Với đồ thị hai phía trong hình vẽ dưới đây và bộ ghép M = {(x[1], y[1]), (x[2], y[2])}

x[3] và y[3] là những đỉnh nhạt, các đỉnh khác là đỉnh đậm

Đường (x[3], y[2], x[2], y[1]) là đường pha

Đường (x[3], y[2], x[2], y[1], x[1], y[3]) là đường mở

Trang 10

X Y

2.1.2 Thuật toán đường mở

Thuật toán đường mở để tìm một bộ ghép lớn nhất phát biểu như sau:

Bước 1:

Bắt đầu từ một bộ ghép bất kỳ M (thông thường bộ ghép được khởi gán

bằng bộ ghép rỗng hay được tìm bằng thuật toán tham lam)

Bước 2:

Tìm một đường mở

Bước 3:

• Nếu bước 2 tìm được đường mở thì mở rộng bộ ghép M: Trên đường mở,

loại bỏ những cạnh đã ghép (cạnh đậm) khỏi M và thêm vào M những cạnh chưa

ghép (cạnh nhạt) Sau đó lặp lại bước 2

• Nếu bước 2 không tìm được đường mở thì thuật toán kết thúc

Người ta đã chứng minh được chi phí thời gian thực hiện giải thuật này

trong trường hợp xấu nhất sẽ là O(n3) đối với đồ thị dày và O(n(n+m)logn) đối

với đồ thị thưa

2.2 bài toán tìm bộ ghép cực đại với tổng trọng số cực

đại hoặc cực tiểu trên đồ thị hai phía

2.2.1 Bài toán phân công

Đây là dạng bài toán phát biểu như sau: Một xí nghiệp có N công nhân và

dây chuyền sản xuất có M máy Nếu công nhân i đứng ở máy j thì sẽ tạo lợi

nhuận cho nhà máy là C(i,j) Hãy bố trí công nhân sao cho không quá một công

Trang 11

nhân ở một máy và mỗi công nhân làm không quá một máy mà tổng lợi nhuận là lớn nhất

+ Tạo nhãn ban đầu chấp nhận được Fx và Fy theo quy tắc:

Fx[i] = Max( C[i,j], Vj: 1 <= j <= M) Fy[j] = 0, Vj: 1 <= j <= M

(FX, FY gọi là chấp nhận được nếu thoả mãn bất đẳng thức Fx[i] + Fy[j] >= C[i,j])

Nếu Fx[i] + Fy[j] = C[i,j] thì ta coi cạnh (i,j) là cạnh đậm (là đã ghép máy

i cho công nhân j), các cạnh còn lại là cạnh nhạt Hai đầu cạnh đậm là đỉnh đậm, các đỉnh còn lại là đỉnh nhạt

Vậy bằng cách tạo nhãn ban đầu như trên chúng ta có cặp ghép M ban đầu (ghép được một số máy với công nhân tạo lợi nhuận trên các máy đó)

Tìm dây chuyền (bằng logic hoặc đệ qui)

Nếu không có dây chuyền thì sửa nhãn

Ngược lại tăng cặp ghép trên dây chuyền này

Cho đến khi tìm được dây chuyền;

End;

Trang 12

Trong thuật toán trên phải thực hiện các thao tác: tìm dây chuyền, sửa nhãn và tăng cặp ghép

Sửa nhãn: Phải thực hện khi dây chuyền không kết thúc được bằng đỉnh nhạt bên

Y mà kết thúc bằng đỉnh đậm bên X (ta gọi là dây chuyền “dở dang”) Trên các cung nối một đỉnh bên X đã nạp vào dây chuyền tới các đỉnh j thuộc Y chưa thuộc dây chuyền, chọn giá trị bé nhất trong các giá trị: Fx[i] + Fy[j] – C[i,j] Giá trị này được chọn làm lượng sửa nhãn (kí hiệu là m) Sửa nhãn theo cách như sau: Nhãn các đỉnh của X thuộc dây chuyền sẽ giảm đi một lượng là m, nhãn các đỉnh của Y thuộc dây chuyền sẽ tăng thêm một lượng là m, để đảm bảo Fx[i] + Fy[j] – C[i,j] >= 0 Sau khi các đỉnh thuộc dây chuyền “dở dang” đã được sửa nhãn thì nó

có khả năng mới kết hợp với các đỉnh j bên Y tạo nên một dây chuyền hoàn chỉnh (vì sẽ xuất hiện những cặp (i,j) mới mà Fx[i] + Fy[j] = C[i,j])

Tăng cặp ghép: Đổi màu các cung, bắt đầu từ cung nhạt cuối cùng của dây

chuyền đổi ngược dần về cung nhạt đầu tiên của dây chuyền

Tìm dây chuyền: Có thể tìm kiếm theo chiều sâu hoặc tìm kiếm theo chiều rộng

Yêu cầu dây chuyền xuất phát từ một đỉnh nhạt của X, kết thúc bằng một đỉnh nhạt của Y, đồng thời các cung nhạt và đậm liên tiếp xen kẽ nhau (do cung đầu

và cung cuối đều nhạt, nên số cung nhạt lớn hơn số cung đậm là 1)

* Nếu là bài toán tìm tổng nhỏ nhất thì đổi dấu C[i,j] và cuối cùng đổi dấu tổng hoặc khởi trị C[i,j] = vô cùng, nhãn ban đầu V i Є X: Fx[i] = Min { C[i,j] V j Є Y}, Fy[j] = 0, V j Є Y Lượng sửa nhãn m = Min { C[i,j] – Fx[i] – Fy[j] }

2.2.3 Thuật toán Hung-ga-ri

Bài toán: Có N người (số hiệu i = 1, 2, , N) và N công việc (số hiệu j = 1,

2, , N) Để giao việc j cho người i thực hiện cần chi phí là Cij không âm Vấn đề

là cần phân cho người nào làm việc gì (mỗi người chỉ làm một việc, mỗi việc chỉ

do một người làm) sao cho chi phí tổng cộng là nhỏ nhất

Một trong các phương pháp giải bài toán này là tìm cặp ghép có tổng trọng

số trên các cung đạt giá trị nhỏ nhất trên đồ thị hai phía Nhưng cũng có thể giải bằng phương pháp Hung-ga-ri được xây dựng trên cơ sở các định lý sau đây:

Trang 13

Định lí 1: Nếu ma trận chi phí C(N,N) có N số 0 mà không có số 0 nào cùng

hàng hoặc cùng cột thì có phương án tối ưu là: Nếu số 0 ở (i,j) thì phân công người i làm việc j

Định lí 2: Nếu thay ma trận C(N,N) bởi ma trận C’(N,N) bằng cách trừ mỗi phần

tử trong một hàng (hoặc cột) cho phần tử nhỏ nhất của hàng đó (hoặc cột đó) thì phương án tối ưu không thay đổi khi tìm phương án này trên C’(N,N)

Thuật toán

Bước 1:

Thực hiện trên ma trận chi phí C: Trừ mỗi hàng cho phần tử nhỏ nhất trên hàng đó Trừ mỗi cột cho phần tử nhỏ nhất trên cột đó Kết quả thu được ma trận C’ có tính chất: trên mỗi hàng, trên mỗi cột có ít nhất một số 0 (ta kí hiệu những

Lần lượt từ hàng 1 đến hàng N, tìm hàng đầu tiên không chứa ô Đ (giả sử

đó là hàng i0) Tìm ô T trên hàng i0, chẳng hạn ở cột j0 Xuất phát từ ô T(i0,j0) này

ta xây dựng một dây chuyền các ô kế tiếp nhau theo cột rồi theo hàng xen kẽ các

ô T và Đ Giả sử đã có dây chuyền T(i0,j0), Đ( i1,j0), T(i1,j1), , ta tìm tiếp theo cách thức sau:

+ (3-A): Nếu đã tìm đến ô T(ik,jk) ta tìm ô T trong cột jk không cùng dòng với ô Đ nào đã có trong dây chuyền đang xét Nếu tìm thấy T ở dòng ik+1 thì gán lại kí hiệu T của ô này thành Đ được ô Đ(ik+1,jk) và thêm nó vào dây chuyền rồi chuyển tới bước (3-B), trái lại ta được một dây chuyền bắt đầu là ô T(i0,j0) và kết thúc tại ô T(ik,jk), ta đổi kí hiệu màu các ô trên dây chuyền (T thành Đ và ngược lại – nghĩa là tăng luồng trên dây chuyền) Nếu đủ N ô Đ thì dừng, trái lại trở về

đầu bước 3 tìm hàng tiếp theo không chứa ô Đ

Trang 14

+ (3-B): Nếu đã đến ô Đ(ik+1,jk), ta tìm trên hàng ik+1 ô T không cùng cột với bất kì ô nào đã có mặt trong dây chuyền đang xét Nếu tìm được trên cột jk+1thì thêm ô T(ik+1,jk+1) vào dây chuyền rồi chuyển tới (3-A) Trong trường hợp ngược lại thì dây chuyền xuất phát từ T(i0,j0) và kết thúc tại Đ(ik+1,jk) và không thể tăng luồng trên dây chuyền này được (vì số ô T bằng số ô Đ) Ta sẽ loại khỏi dây chuyền các ô T(ik,jk) và Đ(ik+1,jk) đồng thời đánh dấu cột jk là cột “trở ngại”, lui về

ô Đ(ik,jk-1) tiếp tục mở rộng dây chuyền nếu trên hàng ik còn có ô T khác với ô T(ik,jk) không nằm trên cột “trở ngại” và các cột đã có mặt trong dây chuyền đang xét, nghĩa là ta lặp lại bước (3-B) với hàng ik

Nếu không tiếp tục mở rộng được dây chuyền theo cách trên nữa thì tìm ô

T trên dòng i0 ở cột j0 không là cột “trở ngại” Nếu ô T như thế tồn tại thì bắt đầu lặp lại (3-A), ngược lại chuyển sang bước 4

“trở ngại” với m

Quay về bước 2 với ma trận mới thu được là C’ đóng vai trò là C

2.2.4 Phương pháp đối ngẫu Kuhn-Munkres

Phương pháp đối ngẫu Kuhn-Munkres đi tìm hai dãy số Fx[1 k] và Fy[1 k] thoả mãn:

• C[i,j] – Fx[i] – Fy[j] >= 0

• Tập các cạnh (x[i], y[j]) thoả mãn C[i,j] – Fx[i] – Fy[j] = 0 chứa trọn một bộ ghép đầy đủ k cạnh, đây chính là bộ ghép cần tìm

Rõ ràng nếu tìm được hai dãy số thoả mãn trên thì ta chỉ việc thực hiện hai thao tác:

+ Với mỗi đỉnh x[i], trừ tất cả trọng số của những cạnh liên thuộc với x[i] đi một lượng Fx[i]

Trang 15

+ Với mỗi đỉnh y[j], trừ tất cả trọng số của những cạnh liên thuộc với y[j] đi một lượng Fy[j]

(Hai thao tác này tương đương với việc trừ tất cả trọng số của các cạnh (x[i], y[j])

đi một lượng Fx[i] + Fy[j] tức là C[i,j] := C[i,j] – Fx[i] – Fy[j])

Thì dễ thấy đồ thị mới tạo thành sẽ gồm có các cạnh trọng số không âm và những cạnh có trọng số bằng 0 của đồ thị chứa trọn một bộ ghép đầy đủ

Vậy phương pháp đối ngẫu Kuhn-Munkres đưa việc biến đổi đồ thị G (biến đổi ma trận C) về việc biến đổi hai dãy số Fx và Fy Việc trừ một lượng delta vào trọng số tất cả các cạnh liên thuộc với x[i] tương đương với việc tăng Fx[i] lên một lượng delta Việc cộng một lượng delta vào trọng số tất cả các cạnh liên thuộc với y[j] tương đương với việc giảm Fy[j] đi một lượng delta Khi cần biết trọng số cạnh (x[i], y[j]) là bao nhiêu sau các bước biến đổi, thay vì viết C[i,j], ta viết C[i,j] – Fx[i] – Fy[j]

Sơ đồ cài đặt phương pháp đối ngẫu Kuhn-Munkres có thể viết như sau:

Bước 1: Khởi tạo:

• M := O;

• Việc khởi tạo các Fx, Fy có thể có nhiều cách miễn sao C[i,j] – Fx[i] – Fy[j] >=

0, đơn giản nhất có thể đặt tất cả các Fx[.], Fy[.] bằng 0

Bước 2: Với mọi đỉnh x* Є X, ta tìm cách ghép x* như sau:

Bắt đầu từ đỉnh x*, thử tìm đường mở bắt đầu ở x* bằng thuật toán tìm kiếm trên đồ thị (BFS hoặc DFS) Có hai khả năng xảy ra:

+ Hoặc tìm được đường mở thì dọc theo đường mở, ta loại bỏ những cạnh đã ghép khỏi M và thêm vào M những cạnh chưa ghép

+ Hoặc không tìm được đường mở thì xác định được:

VisitedX = { Tập những X_đỉnh có thể đến được từ x* bằng một đường pha}

VisitedY = { Tập những Y_đỉnh có thể đến được từ x* bằng một đường pha}

Đặt delta = min { C[i,j] – Fx[i] – Fy[j] | Vx[i] Є VisitedX, Vy[j] Є VisitedY}

Với Vx[i] Є VisitedX: Đặt Fx[i] := Fx[i] + delta;

Trang 16

Với Vy[j] Є VisitedY: Đặt Fy[j] := Fy[j] - delta;

Lặp lại thủ tục tìm đường mở xuất phát tại x* cho tới khi tìm ra đường mở

ma trận chi phí C là không thể thực hiện được

2.2.5 Nâng cấp

Dựa vào sơ đồ cài đặt thuật toán Kuhn-Munkres ở trên, ta có thể đánh giá

độ phức tạp tính toán lý thuyết của cách cài đặt này:

Thuật toán tìm kiếm theo chiều rộng được sử dụng để tìm đường mở có độ phức tạp O(k2), mỗi lần xoay trọng số cạnh mất một chi phí thời gian cỡ O(k2) Vậy, mỗi lần tăng cặp cần tối đa k lần dò đường và k lần xoay trọng số cạnh, mất một chi phí thời gian cỡ O(k3) Thuật toán cần k lần tăng cặp nên độ phức tạp tính toán trên lý thuyết của phương pháp này cỡ O(k4) Có thể cải tiến mô hình cài đặt

để được một thuật toán với độ phức tạp O(k3) dựa trên những nhận xét sau:

Nhận xét 1:

Quá trình tìm kiếm theo chiều rộng bắt đầu từ một đỉnh x* chưa ghép cho

ta một cây pha gốc x* Nếu tìm được đường mở thì dừng lại và tăng cặp ngay, nếu không thì xoay trọng số cạnh và bắt đầu tìm kiếm lại để được một cây pha lớn hơn cây pha cũ

Nhận xét 2:

Việc xác định trọng số nhỏ nhất của cạnh nối một X_đỉnh trong cây pha với một Y_đỉnh ngoài cây pha có thể kết hợp ngay trong bước dựng cây pha mà không làm tăng cấp phức tạp tính toán Để thực hiện được điều này, ta sử dụng kỹ thuật sau:

Trang 17

Với mọi y[j] Є Y, gọi d[j] là khoảng cách từ y[j] đến cây pha gốc x* Ban

đầu d[j] được khởi tạo bằng trọng số cạnh (x*,y[j]) (cây pha ban đầu chỉ có đúng một đỉnh x*)

Trong bước tìm đường bằng BFS, mỗi lần rút một đỉnh x[i] ra khỏi Queue,

ta xét những đỉnh y[j] Є Y chưa thăm và đặt lại d[j]mới := min(d[j]cũ, trọng số cạnh (x[i], y[j])) sau đó mới kiểm tra xem (x[i],y[j]) có phải là cạnh có trọng số bằng 0 hay không để tiếp tục các thao tác như trước Nếu quá trình BFS không tìm ra

đường mở thì giá trị xoay delta chính là giá trị nhỏ nhất trong các d[j] dương Ta bớt được một đoạn chương trình tìm giá trị xoay có độ phức tạp O(k2) Công việc tại mỗi bước xoay chỉ là tìm giá trị nhỏ nhất trong các d[j] dương và thực hiện phép cộng, trừ trên hai dãy đối ngẫu Fx và Fy, nó có độ phức tạp tính toán O(k) Tối đa có k lần xoay để tìm đường mở nên tổng chi phí thời gian thực hiện các lần xoay cho tới khi tìm ra đường mở cỡ O(k2) Lưu ý rằng đồ thị đang xét là đồ thị hai phía đầy đủ nên khi xoay các trọng số cạnh bằng giá trị xoay delta, tất cả các cạnh nối từ X_đỉnh trong cây pha tới Y_đỉnh ngoài cây pha đều bị giảm trọng số

đi delta, chính vì vậy sau mỗi bước xoay, ta phải trừ tất cả các d[j]> 0 đi delta để giữ được tính hợp lý của các d[j]

Nhận xét 4:

Thủ tục tăng cặp dựa trên đường mở có độ phức tạp O(k)

Trang 18

Từ 3 nhận xét trên, phương pháp đối ngẫu Kuhn-Munkres có thể cài đặt bằng một chương trình có độ phức tạp tính toán O(k3) bởi nó có k lần tăng cặp và chi phí cho mỗi lần là O(k2)

2.3 Bài toán tìm bộ ghép cực đại trên đồ thị tổng quát 2.3.1 Các khái niệm

Xét đồ thị G = (V, E), một bộ ghép trên đồ thị G là một tập các cạnh đôi một không có đỉnh chung

Bài toán tìm bộ ghép cực đại trên đồ thị tổng quát phát biểu như sau: Cho một đồ thị G, phải tìm một bộ ghép cực đại trên G (bộ ghép có nhiều cạnh nhất)

Với một bộ ghép M của đồ thị ta gọi:

+ Những cạnh thuộc M được gọi là cạnh đã ghép hay cạnh đậm

+ Những cạnh không thuộc M được gọi là cạnh chưa ghép hay cạnh nhạt

+ Những đỉnh đầu mút của các cạnh đậm được gọi là đỉnh đã ghép, những đỉnh còn lại gọi là đỉnh chưa ghép

+ Một đường đi cơ bản (đường đi không có đỉnh lặp lại) được gọi là đường pha

nếu nó bắt đầu bằng một cạnh nhạt và tiếp theo là các cạnh đậm, nhạt nằm nối tiếp xen kẽ nhau

+ Một chu trình cơ bản (chu trình không có đỉnh trong lặp lại) được gọi là một

Blossom nếu nó đi qua ít nhất 3 đỉnh, bắt đầu và kết thúc bằng cạnh nhạt và dọc

trên chu trình, các cạnh đậm, nhạt nằm nối tiếp xen kẽ nhau Đỉnh xuất phát của

chu trình (cũng là đỉnh kết thúc) được gọi là đỉnh cơ sở của Blossom

+ Đường mở là một đường pha bắt đầu ở một đỉnh chưa ghép và kết thúc ở một

đỉnh chưa ghép

Ví dụ:

Với đồ thị G và bộ ghép M trong hình vẽ dưới đây

Đường (8, 1, 2, 5, 6, 4) là một đường pha

Chu trình (2, 3, 4, 6, 5, 2) là một Blossom

Đường (8, 1, 2, 3, 4, 6, 5, 7) là một đường mở

Trang 19

Đường (8, 1, 2, 3, 4, 6, 5, 2, 1, 9) tuy có các cạnh đậm/nhạt xen kẽ nhưng

không phải đường pha (và tất nhiên không phải đường mở) vì đây không phải là

đường đi cơ bản

Ta dễ dàng suy ra được các tính chất sau:

+ Đường mở cũng như Blossom đều là đường đi độ dài lẻ với số cạnh nhạt nhiều

hơn số cạnh đậm đúng 1 cạnh

+ Trong mỗi Blossom, những đỉnh không phải là đỉnh cơ sở đều là đỉnh đã ghép

và đỉnh ghép với đỉnh đó cũng phải thuộc Blossom

+ Vì Blossom là một chu trình nên trong mỗi Blossom, những đỉnh không phải

đỉnh cơ sở đều tồn tại hai đường pha từ đỉnh cơ sở đi đến nó, một đường kết thúc

bằng cạnh đậm và một đường kết thúc bằng cạnh nhạt, hai đường pha này được

hình thành bằng cách đi dọc theo chu trình theo hai hướng ngược nhau Như ví dụ

trên, đỉnh 4 có hai đường pha từ đỉnh cở sở 2 đi tới: (2, 3, 4) là đường pha kết thúc

bằng cạnh đậm và (2, 5, 6, 4) là đường pha kết thúc bằng cạnh nhạt

2.3.2 Thuật toán Edmonds (1965)

Cơ sở của thuật toán là định lý (C.Berge): Một bộ ghép M của đồ thị G là

cực đại khi và chỉ khi không tồn tại đường mở đối với M

Thuật toán Edmonds:

Trang 20

<Dọc trên đường mở: Loại bỏ những cạnh đậm khỏi M; Thêm vào

M những cạnh nhạt>;

<Trả về M là bộ ghép cực đại trên G>;

Điều khó nhất trong thuật toán Edmonds là phải xây dựng thuật toán tìm

đường mở xuất phát từ một đỉnh chưa ghép Thuật toán đó được xây dựng bằng cách kết hợp một thuật toán tìm kiếm trên đồ thị với phép chập Blossom

Xét những đường pha xuất phát từ một đỉnh x chưa ghép Những đỉnh có thể đến được từ x bằng một đường pha kết thúc là cạnh nhạt được gán nhãn

“nhạt” (gọi tắt là đỉnh nhạt), những đỉnh có thể đến được từ x bằng một đường pha kết thúc là cạnh đậm được gán nhãn “đậm” (gọi tắt là đỉnh đậm)

Với một Blossom, ta định nghĩa phép chập (shrink) là phép thay thế các

đỉnh trong Blossom bằng một đỉnh duy nhất Những cạnh nối giữa một đỉnh thuộc Blossom tới một đỉnh v nào đó không thuộc Blossom được thay thế bằng cạnh nối giữa đỉnh chập này với v và giữ nguyên tính đậm/nhạt Có thể kiểm chứng được nhận xét: sau mỗi phép chập, các cạnh đậm vẫn được đảm bảo là bộ ghép trên đồ thị mới

= đỉnh cơ sở của Blossom = đỉnh chập từ Blossom

Trang 21

Thuật toán tìm đường mở xuất phát từ đỉnh x có thể phát biểu như sau: Trước hết đỉnh xuất phát x được gán nhãn đậm

Tiếp theo là thuật toán tìm kiếm trên đồ thị bắt đầu từ x, theo nguyên tắc: từ đỉnh

đậm chỉ được phép đi tiếp theo cạnh nhạt và từ đỉnh nhạt chỉ được đi tiếp theo cạnh đậm Mỗi khi thăm tới một đỉnh, ta gán nhãn đậm/nhạt cho đỉnh đó và tiếp tục thao tác tìm kiếm trên đồ thị như bình thường Cũng trong quá trình tìm kiếm, mỗi khi phát hiện thấy một cạnh nhạt nối hai đỉnh đậm, ta dừng lại ngay vì nếu gán nhãn tiếp sẽ gặp tình trạng một đỉnh có cả hai nhãn đậm/nhạt, trong trường hợp này, Blossom được phát hiện và bị chập thành một đỉnh, thuật toán được bắt

đầu lại với đồ thị mới cho tới khi trả lời được câu hỏi: “có tồn tại đường mở xuất phát từ x hay không?”

Nếu đường mở không đi qua đỉnh chập nào thì ta chỉ việc tăng cặp dọc theo đường mở Nếu đường mở có đi qua một đỉnh chập thì ta lại nở đỉnh chập đó

ra thành Blossom để thay đỉnh chập này trên đường mở bằng một đoạn đường xuyên qua Blossom

Hình vẽ: nở Blossom để dò đường xuyên qua Blossom

Lưu ý rằng không phải Blossom nào cũng bị chập, chỉ những Blossom ảnh hưởng tới quá trình tìm đường mở mới phải chập để đảm bảo rằng đường mở tìm

được là đường đi cơ bản

Trang 22

2.3.3 Thuật toán Lawler (1973)

Trong thuật toán Edmonds, sau khi chập mỗi Blossom thành một đỉnh thì

đỉnh đó hoàn toàn lại có thể nằm trên một Blossom mới và bị chập tiếp Thuật toán Lawler chỉ quan tâm tới đỉnh chập cuối cùng, đại diện cho Blossom ngoài nhất, đỉnh chập cuối cùng này được định danh bằng đỉnh cơ sở của Blossom ngoài nhất

Cũng chính vì thao tác chập/nở nói trên mà ta cần mở rộng khái niệm

Blossom, có thể coi một Blossom là một tập đỉnh nở ra từ một đỉnh chập chứ

không đơn thuần là một chu trình pha cơ bản nữa

Xét một Blossom B có đỉnh cơ sở là đỉnh r Với V v Є B, v = r, ta lưu lại hai đường pha từ r tới v, một đường kết thúc bằng cạnh đậm và một đường kết thúc bằng cạnh nhạt, như vậy có hai loại vết gán cho mỗi đỉnh v (hai vết này được cập nhật trong quá trình tìm đường):

+ S[v] là đỉnh liền trước v trên đường pha kết thúc bằng cạnh đậm, nếu không tồn tại đường pha loại này thì S[v] = 0

+ T[v] là đỉnh liền trước v trên đường pha kết thúc bằng cạnh nhạt, nếu không tồn tại đường pha loại này thì T[v] = 0

Bên cạnh hai nhãn S và T, mỗi đỉnh v còn có thêm:

+ Nhãn b[v] là đỉnh cơ sở của Blossom chứa v Hai đỉnh u và v thuộc cùng một Blossom b[u] = b[v]

+ Nhãn match[v] là đỉnh ghép với đỉnh v Nếu v chưa ghép thì match[v] = 0

Khi đó, thuật toán tìm đường mở bắt đầu từ đỉnh x chưa ghép có thể phát biểu như sau:

Trang 23

Với mỗi đỉnh đậm u lấy ra từ Queue, xét những cạnh nhạt (u, v):

- Nếu v là đỉnh nhạt hoặc b[v] = b[u] ==> bỏ qua

- Nếu v là đỉnh đậm và b[v] = b[u] ta phát hiện được Blossom mới chứa

u và v, khi đó:

Phát hiện đỉnh cơ sở: Truy vết đường đi ngược từ hai đỉnh đậm u

và v theo hai đường pha về nút gốc, chọn lấy đỉnh a là đỉnh đậm chung gặp

đầu tiên trong quá trình truy vết ngược Khi đó Blossom mới phát hiện sẽ

có đỉnh cơ sở là a

Gán lại vết: Gọi (a = i[1], i[2], , i[p] = u) và (a = j[1], j[2], , j[q] =

v) lần lượt là hai đường pha dẫn từ a tới u và v Khi đó (a = i[1], i[2], , i[p]

= u, j[q] = v, j[q-1], , j[1] = a) là một chu trình pha đi từ a tới u và v rồi quay trở về a Bằng cách đi dọc theo chu trình này theo hai hướng ngược nhau, ta có thể gán lại tất cả các nhãn S và T của những đỉnh trên chu trình Lưu ý rằng không được gán lại các nhãn S và T cho những đỉnh k mà b[k] = a, và với những đỉnh k có b[k] = a thì bắt buộc phải gán lại nhãn S

và T theo chu trình này bất kể S[k] và T[k] trước đó đã có hay chưa

Chập Blossom: Xét những đỉnh v mà b[v] Є {b[i[1]], b[i[2]], ,

b[i[p]], b[j[1]], b[j[2]], , b[j[q]]}, gán lại b[v] = a Nếu v là đỉnh đậm (có nhãn S[v] = 0) mà chưa được duyệt tới (chưa bao giờ được đẩy vào Queue) thì đẩy v vào Queue chờ duyệt tiếp tại những bước sau

Bước 3:

Nếu bước 2 tìm được đường mở thì trả về đường mở, nếu bước 2 không tìm thấy đường mở và thoát ra do hàng đợi rỗng thì kết luận không tìm thấy đường

mở

Trang 24

Tư tưởng chính của phương pháp Lawler là dùng các nhãn b[v] thay cho thao tác chập trực tiếp Blossom, dùng các nhãn S và T để truy vết tìm đường mở, tránh thao tác nở Blossom Phương pháp này dựa trên một nhận xét: Mỗi khi tìm

ra đường mở, nếu đường mở đó xuyên qua một Blossom ngoài nhất thì chắc chắn

nó phải đi vào Blossom này từ nút cơ sở và thoát ra ngoài bằng một cạnh nhạt

Trang 25

Chương 3

Giới thiệu ngôn ngữ delphi

Delphi có tiền thân là ngôn ngữ Pascal Có thể nói Delphi là một trong “tứ đại thiên vương” của thế giới ngôn ngữ lập trình hiện nay đó là C/C++, Delphi, Visual Basic và Java Trong số đó chỉ có Delphi là có khả năng sánh ngang và vượt trội ngôn ngữ lập trình C/C++ Trong chương này chúng ta sẽ tìm hiểu một cách khái quát về ngôn ngữ lập trình Delphi

Những vấn đề sẽ được đề cập trong chương này:

 Khái quát về ngôn ngữ Delphi

 Form và các thành phần giao diện

3.1 Khái quát về ngôn ngữ Delphi

3.1.1 Delphi là gì?

Delphi có hạt nhân là trình biên dịch Pascal rất nổi tiếng và quen thuộc Delphi là một bước đột phá tiếp theo của trình biên dịch Pascal, được hãng Borland phát triển liên tục kể từ khi Anders Hejlsberg viết ra trình biên dịch Turbo Pascal đầu tiên cách đây 17 năm Kế thừa mọi đặc tính của Pascal, trình biên dịch của Delphi là sự tổng hợp tinh hoa về kinh nghiệm của Pascal qua hơn một thập kỷ, cộng với kỹ thuật biên dịch được tối ưu hoá dựa trên kiến trúc 32-bit của bộ xử lý Ngôn ngữ Delphi mang tính ổn định, sự uyển chuyển, độ tin cậy cao

Delphi là môi trường ứng dụng “tức thời” RAD (Rapid Application Divelopment) bao gồm ốac công cụ phát triển hệ thống và cơ sở dữ liệu dành cho Microsoft Windows 95/98 và Windows NT Delphi kết hợp sự tiện dụng của môi trường phát triển trực quan, tốc độ và sức mạnh của trình biên dịch 32-bit, khả năng quản lý cơ sở dữ liệu chặt chẽ với hạt nhân (thư viện BDE) uyển chuyển có thể truy suất nhiều loại cơ sở dữ liệu khác nhau Mặc dù bản thân các đặc tính trên không phải là đặc trưng riêng của Delphi nhưng nhìn chung Delphi đã tích hợp các công nghệ riêng rẽ để tạo nên một môi trường phát triển toàn diện, cần thiết và rất hữu ích cho ngành công nghiệp phần mềm hiện nay

Trang 26

a Môi trường phát triển trực quan

Delphi cho phép xây dựng ứng dụng bằng cách chọn các thành phần công cụ

có sẵn từ bảng công cụ đặt chúng vào Form, lắp ghép và tạo nên một ứng dụng hoàn chỉnh Nét đẹp thực sự của môi trường phát triển trực quan là Delphi sẽ tự

động sinh mã khi kết nối các công cụ trên Form Mọi thành phần trong Delphi

được xây dựng trên nền tảng hướng đối tượng vững chắc

b Trình biên dịch 32-bit được tối ưu hoá

Điểm đặc biệt tách rời Delphi với các môi trường phát triển trực quan khác là khả năng biên dịch các chương trình thực thi exe độc lập 32-bit chạy rất nhanh

và hiệu quả Trình biên dịch Delphi cũng đưa ra những chỉ dẫn bổ ích giúp bạn quyết định sự tối ưu, loại bỏ những biến dư thừa không sử dụng đến, thông báo lỗi chính xác

Một ưu điểm nữa, nếu sử dụng chung các sản phẩm của Inprise như Borland C++ Builder chẳng hạn, trình biên dịch Delphi sẽ chia sẻ chung cơ chế biên dịch

và sinh mã, giúp ta dễ dàng trao đổi mã lệnh và thư viện của hai ngôn ngữ Object Pascal và C/C++ với nhau thông qua các tập tin OBJ

c Truy cập và xử lý cơ sở dữ liệu mềm dẻo

Delphi là công cụ lý tưởng để thiết kế các ứng dụng cơ sở dữ liệu ứng dụng Delphi có khả năng giao tiếp và truy xuất nhiều loại cơ sở dữ liệu khác nhau, có thể kết nối với các hệ cơ sở dữ liệu thông qua ODBC, các trình điều khiển dành riêng mà mỗi hệ cơ sở dữ liệu cung cấp, thông qua ADO hay OLE DB của Microsoft

d Ngôn ngữ và thư viện

Delphi sử dụng ngôn ngữ hướng đối tượng Object Pascal Object Pascal cung cấp một tập hợp ngôn ngữ mở rộng hiệu quả và uyển chuyển bao gồm:

- Xử lý lỗi ngoại lệ

- Kiểm tra kiểu dữ liệu thực thi

- Hỗ trợ từ khoá mới Interface

- Kiểu chuỗi không giới hạn

Trang 27

- Kiểu dữ liệu tiền tệ

- Kiểu dữ liệu Variant

Thư viện các thành phần công cụ trực quan VCL (Visual Component Library)

là bộ khung làm việc hướng đối tượng chủ yếu của Delphi, nó bao bọc, che dấu

sự phức tạp của các hàm Windows API dựng để viết các ứng dụng Windows

3.1.2 Cấu trúc chương trình Delphi và Unit

Chương trình được xây dựng từ các đơn thể mã nguồn nhỏ gọi là Unit Mỗi Unit chứa trong một tập tin và được biên dịch độc lập Các Unit dùng để liên kết với nhau tạo thành ứng dụng

a Cấu trúc của chương trình chính và cú pháp

Một chương trình thường bao gồm 3 phần:

- Phần tiêu đề dành cho chương trình

- Mệnh đề Uses

- Các khai báo khối cũng như câu lệnh điều khiển

Tiêu đề của chương trình thường là tên của chương trình chính Mệnh đề

Uses liệt kê và khai báo các Unit mà chương trình sẽ sử dụng Khối được dựng để

chứa các khai báo và câu lệnh điều khiển tạo nên ứng dụng Môi trường phát triển tích hợp IDE của Delphi thường tạo ra tập tin dự án với tên DPR để lưu nội dung chương trình chính

Tiêu đề của chương trình bắt đầu bằng từ khoá Program, tiếp theo là một

định danh hợp lệ và kết thúc bằng dấu chấm phẩy (;), định danh của chương trình phải trùng vói tên của tập tin dự án

Mệnh đề Uses dùng để kết hợp một hay nhiều đơn thể Unit của chương trình

lại với nhau

Khối lệnh của chương trình sẽ bao gồm một hoặc nhiều câu lệnh có cấu trúc

Khối lệnh bắt đầu bằng từ khoá Begin và kết thúc bằng từ khoá End Một khối

lệnh thông thường kết thúc bằng dấu chấm phẩy Tuy nhiên, chương trình chính cũng được coi là một khối lệnh lớn bao trùm các khối lệnh con khác nhưng kết thúc bằng dấu chấm (.)

Trang 28

b Cấu trúc Unit và cú pháp

Unit là một đơn thể độc lập của chương trình Unit bao gồm các khai báo kiểu, hằng, biến và các hàm, thủ tục Mã nguồn của mỗi Unit được đặt trong tập tin PAS

Một Unit bắt đầu bằng tiêu đề, tiếp đến là các phân đoạn Interface, implementation, initialization và finalization

Tiêu đề là phần tên của Unit, bắt đầu bằng từ khoá Unit, tiếp theo là tên định

danh, kết thúc bằng dấu chấm phẩy Tên của Unit phải trùng với tên tập tin chứa Unit và là duy nhất trong toàn bộ dự án

Phân đoạn interface bắt đầu bằng từ khoá interface và kết thúc khi gặp phân

đoạn implementation Phân đoạn này dùng để khai báo các hằng, biến, kiểu, thủ tục và hàm giành cho chương trình hay các Unit khác truy suất đến

Phân đoạn initialization bắt đầu bằng từ khoá initialization và kết thúc khi gặp

từ khoá finalization Mục đích của phân đoạn này là dùng để khởi tạo thư viện Phân đoạn này là tuỳ chọn

3.2 Form và các thành phần giao diện

3.2.1 Xây dựng ứng dụng từ những thành phần công cụ VCL

a Tình huống

Tình huống là những phương thức được gọi để phản hồi lại yêu cầu từ phía người dùng hay hệ thống Mỗi đối tượng VCL có một danh sách các tình huống như:

OnMounseMove Cho biết khi người sử dụng di chuyển chuột lên đối tượng

OnMounseDown Cho biết khi chuột được nhấn lên đối tượng

OnKeyPress Cho đối tượng biết hiện có một phím được gõ

Ngoài những tình huống giống nhau, mỗi đối tượng khác nhau cũng có những tình huống cần xử lý khác nhau tuỳ theo thuộc tính của mỗi đối tượng Ví dụ đối tượng Form sẽ có những tình huống sau đây mà đối tượng Button không có:

Trang 29

OnClose Cho biết tình huống khi người dùng muốn đóng cửa sổ Form OnShow Cho biết tình huống khi Form được hiển thị

b Phương thức xử lý tình huống của đối tượng

Tất cả các phương thức xử lý tình huống trong Delphi đều có ít nhất một đối

số Sender được khai báo như sau: Sender : TObject Ngoài ra, tuỳ theo mỗi tình huống Delphi sẽ đặt thêm một số thông tin cần thiết vào phương thức xử lý để ta biết cách ứng xử

3.2.2 Form

a Form và tình huống OnCreate

Tình huống OnCreate của Form là tình huống thường sử dụng nhất Tình huống này được gọi khi lần đầu tiên Form được khởi tạo Ta có thể xây dựng phương thức xử lý tình huống OnCreate để gán các giá trị ban đầu cho biến, đặt giá trị thuộc tính của những đối tượng trên Form về trạng thái mặc định

b Form và tình huống OnClose

Tình huống OnClose phát sinh khi ta nhấn vào nút bên góc phải của cửa sổ hoặc khi ta gọi phương thức Close() của Form Ta có thể dùng tình huống này để nhận biết quá trình thao tác trên Form của người dùng chấm dứt

c Form và tình huống OnCloseQuery

Tình huống OnCloseQuery của Form được gọi trước tình huống OnClose Windows sẽ hỏi ta có cho phép đóng cửa sổ Form hay không? Nếu đồng ý ta đặt biến CanClose=true (CanClose là tham biến mà Delphi đặt trong tình huống này), Windows sẽ gọi tiếp đến tình huống OnClose Nếu CanClose được đặt giá trị False thì Windows sẽ trở lại với cửa sổ Form mà không làm gì cả

Trang 30

3.2.3 Các thành phần điều khiển của Windows

a Nút nhấn (Button)

Nút nhấn được Delphi đặt trong lớp đối tượng TButton, tình huống thường

được sử dụng nhất của nút nhấn là OnClick Khi người dùng Click chuột vào nút nhấn, tình huống này sẽ được gọi để phản ứng lại bằng một tác vụ nào đó

b Nhãn (Lable)

Nhãn là thành phần đơn giản nhất trong thư viện VCL Đối tượng nhãn chỉ dùng để trình bày một chuỗi văn bản thông thường, nhằm mục đích mô tả thêm thông tin cho các đối tượng khác Nhãn cũng có thể được dùng để đưa kết quả ra màn hình dưới dạng chuỗi

Trong Delphi, nhãn được đặt trong lớp đối tượng có tên là TLable Thuộc tính thường được sử dụng nhất của nhãn là:

- Caption thể hiện nội dung nhãn

- Font định font chữ, kiểu chữ cho nhãn

- Transparent cho phép màu nền của nhãn trùng với màu nền của Form

d Ô chọn (RadioButton)

Không như ô đánh dấu CheckBox được chọn riêng lẻ, các ô chọn (Radio) thường đi chung với nhau và mỗi lần chỉ được thể hiện trạng thái chọn cho một nút chọn

Ô chọn Radio được Delphi đặt trong lớp đối tượng có tên là TRadioButton

Trang 31

Nếu Checked=True, ô chọn đang ở trạng thái được chọn Nếu Checked=False, người dùng dã bỏ chọn ở ô hiện hành để chuyển sang chọn ô khác Khi ô chọn Radio được kích chuột để yêu cầu thay đổi trạng thái, tình huống OnClick sẽ phát sinh

e Ô văn bản (EditBox)

Ô văn bản là thành phần nhập dữ liệu đơn giản nhất dùng giao diện đồ hoạ, nó cho phép nhập vào một chuỗi văn bản, chỉnh sửa, di chuyển con nháy để soạn thảo bằng các phím mũi tên Ô văn bản chỉ cho phép nhập một dòng văn bản duy nhất

Ô văn bản được Delphi đặt trong lớp đối tượng có tên là TEdit Thuộc tính thường được sử dụng nhất của ô văn bản là thuộc tính text Nó trả về một chuỗi, cho biết nội dung dữ liệu mà người dùng nhập vào Mỗi khi dữ liệu hay nội dung của thuộc tính text thay đổi, tình huống OnChange sẽ được gọi

f Vùng văn bản (Memo)

Vùng văn bản Memo cho phép nhập vào cùng lúc nhiều dòng dữ liệu Có thể dùng Memo để tạo chương trình soạn thảo văn bản hay dùng để xuất ra một chuỗi văn bản

Vùng văn bản được Delphi đặt trong lớp đối tượng có tên là TMemo Thuộc tính thường được sử dụng nhất của Memo là thuộc tính Lines Thuộc tính Lines

có kiểu String, được dùng để quản lý danh sách các dòng dã liệu mà Memo đang

Để đơn giản, Memo cung cấp thuộc tính Text là một chuỗi bao gồm tất cả các dòng trong Memo cộng lại, mỗi dòng cách nhau bởi ký tự 10 và 13 Tình huống thường được sử dụng nhất của Memo là tình huống OnChange, tình huống này

được gọi khi người dùng thay đổi hoặc thêm dữ liệu vào Memo

g Danh sách (ListBox)

Danh sách chứa một danh sách mục chọn, mỗi mục chọn thường được thể hiện là một chuỗi ListBox cho phép chọn mỗi lần một hay nhiều mục cùng lúc Danh sách được Delphi đặt trong lớp đối tượng có tên là TlistBox Thuộc tính thường được sử dụng nhất của danh sách là:

Trang 32

- Items Dùng để thêm bớt các mục chọn vào danh sách

- ItemIndex Cho biết hoặc thiết lập mục chọn hiện hành

- Selected Kiểm tra xem một mục chọn trong danh sách có được chọn hay không

- MultiSelect Cho phép danh sách được chọn đồng thời nhiều mục

- Sorted Tự động sắp xếp các mục chọn theo thứ tự ABC

Các tình huống mà ListBox thường hay phát sinh là:

- OnClick Khi người dùng kích chuột vào mục chọn

- OnDblClick Khi người dùng kích đôi chuột vào một mục

- OnKeyPress Khi người dùng nhấn phím để chọn một mục

- OnKeyDown/ OnKeyUp Xử lý khi người dùng nhấn và nhả phím

- Text Nội dung của mục chọn hiện hành

- Items Danh sách các mục chọn

- ItemIndex Lấy về hoặc thiết lập mục chọn hiện hành cho ComboBox

- Sorted Cho phép sắp xếp các mục chọn trong danh sách theo thứ tự ABC

- Style Chọn các kiểu ComboBox mở rộng

Tình huống mà Litsbox thường phát sinh là tình huống OnChange, được gọi khi nội dung của mục chọn hiện hành bị thay đổi

i Thanh trượt (Scrollbar)

Thanh trượt gồm mũi tên ở hai đầu và một thanh trượt đặt giữa để xác định vị trí Khoảng cách giữa hai đầu thanh trượt và vị trí định vị được biểu hiện bằng các thuộc tính min, max, position Khi nhấn phím mũi tên, PageUp, PageDown hoặc kích chuột vào hai đầu thanh trượt sẽ làm cho vị trí nút trượt di chuyển dần đến hai biên

Thanh trượt được Delphi đặt trong lớp đối tượng có tên là TScrollbar

Trang 33

Thuộc tính thường được sử dụng nhất của thanh trượt Scrollbar là:

- Min Thể hiện giới hạn dưới của thanh trượt

- Max Thể hiện giới hạn trên của thanh trượt

- Position Cho biết hoặc đặt lại vị trí hiện hành của nút trượt

- Kind Cho phép đặt thanh trượt đứng hoặc ngang

- SmallChange Bước nhảy cho thanh trượt khi phím mũi tên được nhấn

- PageSize Bước nhảy cho thanh trượt khi PageUp/PageDown được nhấn Tình huống mà thanh trượt Scrollbar thường phát sinh là OnChange, nó được gọi khi vị trí của nút trượt thay đổi

j Nhóm các ô chọn (RadioGroup)

RadioGroup là đối tượng giúp cho việc gom các nút chọn có cùng một chức năng lại với nhau thành một nhóm duy nhất Thành phần này được Delphi đặt trong lớp đối tượng có tên là TRadioGroup

Thuộc tính thường được sử dụng nhất của thành phần này là:

- Items Các ô chọn RadioButton gắn trong nhóm

- ItemIndex Nút Radio đang được chọn

- Caption Tiêu đề của nhóm ô chọn

Tương tự TRadioGroup, TGroupBox cũng dùng thuộc tính Caption để thể hiện tiêu đề cho nhóm TGroupBox cũng cung cấp các tình huống như OnClick, OnMouseUp, OnMouseDown … nhưng hầu như rất ít khi dùng đến chúng, nó thường chỉ được dùng với mục đích gom các đối tượng lại với nhau theo chủ đề

Nó đóng vai trò như một vật chứa

Trang 34

l Bảng chứa (Panel)

Bảng chứa dùng để gom, nhóm các đối tượng con lại với nhau Thành phần bảng chứa Panel được Delphi đặt trong lớp đối tượng có tên là TPanel

Các thuộc tính thường được sử dụng nhất của Panel là:

- Align Canh lề cho bảng chứa

- BevelInner Đường viền trong

- BevelOuter Đường viền ngoài

- BevelWidth Độ dày của đường viền

- Visibled Cho phép bảng chứa hiển thị hoặc không

m Trình đơn chính (MainMenu)

Trình đơn chính MainMenu là một dãy các lựa chọn nằm phía trên cửa sổ

Đối tượng này được Delphi đặt tên là TMainMenu

n Trình đơn tắt (PopupMenu)

Trình đơn tắt thường hiển thị khi người dùng kích phím phải chuột lên Form hoặc lên một đối tượng nào đó Đối tượng này được Delphi đặt tên là TPopupMenu

3.3 Ngôn ngữ Object Pascal

3.3.1 Các kiểu dữ liệu đơn giản

Delphi phát triển thêm các kiểu dữ liệu sau:

a Kiểu nguyên

Type Range of Values Byte of

Memory Required

Trang 35

d KiÓu Ký tù

Character Type Size in Byte What It Can Hold

ANSIChar 1 One Ansi

erminated

ShortString 255 ANSIChar No AnsiString up to ~3 GB ANSIChar Yes String either 255 or up to ~3GB ANSIChar Yes WideString up to ~1.5 GB WideChar Yes

Trang 36

3.3.2 Các kiểu dữ liệu có cấu trúc

a Mảng (Array)

Mảng dựng để biểu diễn một tập hợp các phần tử có cùng kiểu dữ liệu Mỗi phần tử của mảng được truy suất theo một chỉ số duy nhất

+ Cú pháp xây dựng mảng tĩnh:

Array [ indexType 1,…,indexType n ] Of baseType;

Trong đó: indexType là một tập các số có kiểu thứ tự dựng làm chỉ số mảng baseType là kiểu sẽ được áp dụng cho các phần tử mảng

+ Cú pháp xây dựng mảng động:

Array of array of …of baseType;

Trong khai báo mảng động, số phần tử của mảng chưa được chỉ định Muốn

sử dụng mảng cần phải chỉ định rõ cần chính xác bao nhiêu phần tử để chương trình cấp phát bằng lệnh sau:

Setlength(Name, Value_1, …, Value_n);

Trong đó, Name là tên mảng, Value là số lượng phần tử cần được cấp phát theo mỗi chiều của mảng

Để giải phóng vùng nhớ cấp phát cho marng động ta gọi lệnh gán như sau: Name:=nil;

Chỉ số của các phần tử trong mảng được đánh số bắt đầu từ 0

b Kiểu Record

Kiểu Record là một tập hợp gồm nhiều phần tử có các kiểu khác nhau hợp lại Mỗi phần tử trong cấu trúc bản ghi được gọi là trường

Cú pháp khai báo kiểu bản ghi:

Type recordTypeName = Record

c Kiểu miền con (Subrange Type)

Kiểu miền con của một kiểu rời rạc là một miền trị của kiểu rời rạc đó

Trang 37

Cú pháp khai báo kiểu miền con:

d Kiểu tập hợp (Set type)

Kiểu tập hợp là một tập các giá trị có cùng kiểu thứ tự Mỗi biến kiểu tập hợp có thể chứa nhiều phần tử của tập hợp Tập hợp chỉ chứa được tối đa 256 phần tử, bao gồm cả tập hợp rỗng

Cú pháp khai báo: Set of baseType;

Trong đó baseType là kiểu thứ tự bất kỳ có số phần tử không quá 256

3.3.3 Các câu lệnh cấu trúc

a Câu lệnh IF

Dạng 1:

If expression then statement;

Trong đó, expression là một biểu thức logic Nếu expression trả về giá trị

đúng thì lệnh statement được thực hiện, nếu không chương trình sẽ chuyển điều

khiển xuống dòng lệnh kế tiếp

Dạng 2:

If expression then statement 1 Else statement 2;

Trong đó, expression là một biểu thức logic Nếu expression trả về giá trị

đúng thì lệnh statement 1 sẽ được thực hiện, ngược lại, nếu expression trả về giá trị sai thì lệnh statement 2 sẽ được thực hiện

Ngày đăng: 02/08/2016, 22:01

Nguồn tham khảo

Tài liệu tham khảo Loại Chi tiết
[1] Nguyễn Cam, Chu Đức Khánh - 1999 - Lý thuyết đồ thị - Nhà xuất bản Thành Phố Hồ Chí Minh Sách, tạp chí
Tiêu đề: Lý thuyết đồ thị -
Nhà XB: Nhà xuất bản Thành Phố Hồ Chí Minh
[2] Lê Hữu Đạt, Lê Phương Lan, Hoàng Đức Hải - 2000 - Các kỹ xảo lập trình với Microsoft Visual Basic &amp; Borland Delphi - Nhà xuất bản Giáo dục Sách, tạp chí
Tiêu đề: Các kỹ xảo lập trình với Microsoft Visual Basic & Borland Delphi
Nhà XB: Nhà xuất bản Giáo dục
[3] Nguyễn Xuân My, Hồ Sỹ Đàm, Trần Đỗ Hùng, Lê Sỹ Quang - 2004- Một số vấn đề chọn lọc trong môn tin học (Tập 2) - Nhà xuất bản Giáo dục Sách, tạp chí
Tiêu đề: Một số vấn đề chọn lọc trong môn tin học (Tập 2)
Nhà XB: Nhà xuất bản Giáo dục
[4] Lê Phương Lan, Hoàng Đức Hải - 2003 - Giáo trình lý thuyết &amp; bài tập Delphi - Nhà xuất bản Lao động xã hội Sách, tạp chí
Tiêu đề: Giáo trình lý thuyết & bài tập Delphi
Nhà XB: Nhà xuất bản Lao động xã hội
[5] Đinh Mạnh Trường - 2001 - Cấu trúc dữ liệu và thuật toán – Nhà xuất bản Khoa học và Kỹ thuật Sách, tạp chí
Tiêu đề: Cấu trúc dữ liệu và thuật toán
Nhà XB: Nhà xuất bản Khoa học và Kỹ thuật
[6] Kenneth H.Rosen -2003 - Toán học rời rạc ứng dụng trong tin học - Nhà xuất bản Khoa học và Kỹ thuật - Hà Nội Sách, tạp chí
Tiêu đề: Toán học rời rạc ứng dụng trong tin học
Nhà XB: Nhà xuất bản Khoa học và Kỹ thuật - Hà Nội
[7] Graph Theory ­ith Applicatiins to Engineening and Computer Science, Narsingh Deo, New Delhi - 110001 - 1989 Khác

HÌNH ẢNH LIÊN QUAN

1.2  Đồ thị hai phía - Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế
1.2 Đồ thị hai phía (Trang 8)
Đồ thị hai phía được ứng dụng phổ biến nhất trong việc giải các bài toán - Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế
th ị hai phía được ứng dụng phổ biến nhất trong việc giải các bài toán (Trang 8)
Hình thành bằng cách đi dọc theo chu trình theo hai hướng ngược nhau. Như ví dụ - Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế
Hình th ành bằng cách đi dọc theo chu trình theo hai hướng ngược nhau. Như ví dụ (Trang 19)
Hình vẽ: Phép chập Blossom - Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế
Hình v ẽ: Phép chập Blossom (Trang 20)
Hình vẽ: nở Blossom để dò đường xuyên qua Blossom - Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế
Hình v ẽ: nở Blossom để dò đường xuyên qua Blossom (Trang 21)
Bảng  chứa  dùng  để  gom,  nhóm  các  đối  tượng  con  lại  với  nhau. Thành  phần  bảng chứa Panel được Delphi đặt trong lớp đối tượng có tên là TPanel - Ứng dụng lý thuyết đồ thị giải một số bài toán trong thực tế
ng chứa dùng để gom, nhóm các đối tượng con lại với nhau. Thành phần bảng chứa Panel được Delphi đặt trong lớp đối tượng có tên là TPanel (Trang 34)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w