Tổ chức dữ liệu cho thuật toán

Một phần của tài liệu các thuật toán về đường đi và chu trình euler và ứng dụng (Trang 39 - 65)

Theo phương án cài đặt trên, mỗi cạnh được duyệt 1 lần vào lúc tiến và có thể duyệt thêm 1 lần vào lúc lùi, như vậy sẽ duyệt tối đa 2m lần. Nhận thấy hai thủ tục Tìm đỉnh tiếp đòi hỏi duyệt một dòng của ma trận kề do đó có độ phức tạp O(n). Hơn thế nữa,

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

thủ tục Lui còn duyệt gần như toàn bộ ma trận kề, nghĩa là có độ phức tạp O(n2 ). Do thủ tục này nằm trong vòng lặp của thủ tục chính Euler, nên tổng hợp lại, độ phức tạp của phương án cài đặt này là O(m.n2

).

Chúng ta sẽ tập trung cải tiến thủ tục Tiến và Lui. Muốn vậy ta cố gắng vận dụng các phép truy nhập trực tiếp tới các đỉnh liên thông, tức là đỉnh kề với một đỉnh cho trước. Như trên đã nói, muốn tìm đỉnh j nào kề với đỉnh i cho trước ta phải duyệt dòng c[i] trong ma trận kề c để xác định chỉ số j thoả điều kiện c[i][j] > 0, tức là ta phải bỏ qua tối đa n-1 giá trị c[i][j] = 0 trong quá trình duyệt từ 1 đến n. Nếu với mỗi đỉnh i ta có cách nào nhận được ngay đỉnh j kề với i mà không cần duyệt tuần tự thì độ phức tạp cho thủ tục tìm đỉnh j kề với đỉnh i sẽ giảm còn O(1). Giải pháp ở đây là: ta đặt tất cả đỉnh kề với đỉnh i lên đầu dòng cần duyệt. Khi đó, chỉ cần lấy phần tử đầu tiên là được. Tuy nhiên ta sẽ gặp 2 khó khăn. Thứ nhất, sau khi chọn được đỉnh j kề với đỉnh i ta đưa cạnh (i,j) vào đường đi thì ta cần xoá cạnh đó khỏi đồ thị để các bước sau ta không lấy lại. Thứ hai, vì đồ thị là vô hướng nên ta phải xoá đồng thời hai cạnh (i,j) và (j,i), tức là xoá trên 2 dòng, dòng i và dòng j. Tổ chức danh sách (DS) sẽ giải quyết trọn vẹn hai khó khăn này. Ta sẽ thay mỗi dòng c[i] của ma trận kề c bằng một DS cc[i] chứa các đỉnh kề với đỉnh i. Khi đọc dữ liệu, gặp cạnh (i,j) ta sẽ nạp đồng thời đỉnh j vào DS cc[i] và đỉnh i vào DS c[j]. Thí dụ, cạnh (5, 1) hai dòng c[1] và c[5]:

c[1] = (*, *, *, *, 1, *); c[5] = (1, *, *, *, *, *); dấu * biểu diễn một giá trị nào đó. Nếu dùng DS thì ta có biểu diễn sau:

cc[1] (5, u) ; cc[5] (1, v),

trong đó cho biết DS là hai chiều: mỗi phần tử có hai con trỏ, một trỏ về phần tử kề trước và một trỏ về phần tử kề sau; giá trị 5 tại DS cc[1] cho biết đỉnh kề với đỉnh 1 chính là đỉnh 5, tương tự giá trị 1 tại DS cc[5] cho biết đỉnh kề với đỉnh 5 chính là đỉnh 1; u là con trỏ tới phần tử (1,v) và v là con trỏ tới phần tử (5,u). [3]

Tại sao cần các con trỏ u và v? Khi cần xoá cạnh (i,j) ta phải xoá đồng thời 2 cạnh (i,j) và (j,i), do đó ta phải có cầu nối từ đỉnh i tới đỉnh j và ngược lại. Tổ chức này cho

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

phép ta "nhảy" trực tiếp từ một nút biểu diễn đỉnh i sang nút biểu diễn đỉnh j và ngược lại.

Tại sao cần dùng danh sách 2 chiều? Khi cần xoá một phần tử nào đó của DS ta cần tháo phần tử đó khỏi DS rồi mới xoá. Muốn tháo một phần tử t khỏi DS ta cần truy nhập tới phần tử sát trước và sát sau của t. DS tuyến tính 1 chiều đòi hỏi ta phải duyệt từ đầu DS mới tìm được phần tử sát trước t. Tổ chức 2 chiều cho phép ta đứng tại t "nhảy" ngay đến phần tử sát trước.

Tóm lại, với DS 2 chiều ta quản lí được các đỉnh kề và như vậy là ta quản lí được các cạnh.

Mỗi phần tử của DS cc[i] được khai báo với 4 trường dữ liệu: Trường Vert: chứa đỉnh kề j với đỉnh i;

Trường Pred: trỏ tới phần tử sát trước trong cùng DS; Trường Next: trỏ tới phần tử sát sau trong cùng DS;

Trường Adj: trỏ tới phần tử chứa đỉnh i trong danh sách cc[j]. typedef struct Elem {

int Vert; // vertex (dinh) Elem * Pred; // tro truoc Elem * Next; // Tro sau

Elem * Adj; // Tro toi dinh thuoc cung canh };

Mỗi khi đọc cạnh (i,j) ta sinh ra 2 phần tử: phần tử chứa đỉnh j được gắn vào đầu DS cc[i], phần tử chứa đỉnh i được gắn vào đầu DS cc[j].

void Add(int i, int j) {

Elem *p = NewElem(j,NULL,cc[i]); Elem *q = NewElem(i,p,cc[j]); cc[i]->Pred = p; cc[j]->Pred = q; cc[i] = p; cc[j] = q; p->Adj = q; }

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

Mỗi khi chấp nhận cạnh (i,j) vào chu trình Euler ta xoá đồng thời hai phần tử: phần tử chứa đỉnh j trong DS cc[i] và phần tử chứa đỉnh i trong DS cc[j]. Chú ý rằng, theo tiến độ của thuật toán, phần tử chứa đỉnh j trong DS cc[i] luôn luôn là phần tử đầu của cc[i], nhưng phần tử chứa đỉnh i trong DS cc[j] có thể nằm giữa DS. Ngoài con trỏ sau, con trỏ trước được sử dụng trong tình huống này.

// Xoa phan tu dau danh sach i // va phan tu ke Adj

void Del(int i){

Elem *p = cc[i]; // dau trai Elem *q = p->Adj; // dau phai int j = p->Vert;

if (j == 0) return; /* Gap phan tu dem, danh sach cc[i] rong */

cc[i] = p->Next; cc[i]->Pred = cc[i]; delete p;

if (q->Pred == q) { // q la dau danh sach j cc[j] = q->Next;

cc[j]->Pred = cc[j]; delete q;

return; }

// q o giua danh sach p = q->Pred; // p truoc q

p->Next = q->Next; // thao q khoi danh sach cc[j] (q->Next)->Pred = p;

delete q; }

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

Chƣơng 3

ỨNG DỤNG ĐỒ THỊ EULER

3.1 Bài toán về những cây cầu Königsberg

Bài toán: Trong thành phố Königsberg có hai hòn đảo được nối với nhau và hai bờ sông bằng 7 chiếc cầu như hình sau:

Hình 3.1 Bảy cây cầu bên bờ sông của thành phố Königsberg

Bài toán đặt ra là tìm đường đi qua tất cả 7 cái cầu, mỗi cầu chỉ được qua một lần, sau đó quay trở về nơi xuất phát.

Giải

Để giải bài toán này Euler đã dùng lý thuyết đồ thị thông qua ngôn ngữ đồ thị, ông biểu diễn hai hòn đảo và hai bên bờ sông bằng 4 đỉnh và 7 cây cầu bằng 7 cạnh nối các điểm như sau :

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ Hình 3.2 Đồ thị biểu diễn bảy cây cầu ở hình 3.1

Bài toán yêu cầu tìm đường đi qua tất cả 7 cái cầu, mỗi cầu chỉ được qua một lần, sau đó quay trở về nơi xuất phát, tương đương với việc vẽ đồ thị trên bằng một nét mà kết thúc phải trở về nơi ban đầu đặt nét vẽ. Nói cách khác ta phải đi tìm chu trình Euler của đồ thị này.

Theo định lí Euler thì Đồ thị có chu trình Euler khi và chỉ khi đồ thị đó liên thông và mọi đỉnh bậc chẵn đều khác 0.

Áp dụng vào đồ thị này ta có đồ thị có 4 đỉnh và cả 4 đỉnh này đều là bậc lẻ (k = 4), vì vậy đồ thị này không có chu trình Euler, tức là đồ thị này không thể vẽ bằng 1 nét. Mặt khác đồ thị có 4 đỉnh bậc lẻ nên để vẽ được đồ thị thì tối thiểu phải vẽ bằng 2 nét.

Như vậy thông qua ngôn ngữ đồ thị, Euler đã giải xong bài toán hóc búa này.

3.2. Bài toán về các quân Domino

Domino là một hình chữ nhật chia thành hai hình vuông, mỗi hình mang một trong các số 0, 1, 2, 3, 4, 5, 6. Hai hình vuông trên một Domino có thể mang cùng một số. Có tất cả 28 quân Domino khác nhau. Chứng minh rằng có thể sắp xếp các quân Domino thành hình tròn sao cho hai hình vuông trên hai Domino khác nhau sẽ mang cùng số.

1

2

3

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ Giải

Ta lập đồ thị G có 7 đỉnh V={0, 1, 2, 3, 4, 5, 6}

Mỗi đỉnh có thể nối với các đỉnh còn lại và chính nó để tạo thành Domino ta có đồ thị sau :

Hình 3.3 Đồ thị Domino

Đồ thị này liên thông và tất các các đỉnh đều có bậc chẵn bằng 8. Mỗi cạnh của đồ thị là một quân Domino. Do đó tồn tại chu trình Euler và mỗi chu trình Euler sẽ cho tương ứng một cách xếp. Áp dụng thuật toán Hierholzer tìm một chu trình Euler của đồ thị. 0 4 3 6 5 1 2

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

Xuất phát từ đỉnh 0

Sô đỉnh: 7 Số cạnh: 28

Số đỉnh bậc lẻ là: 0

Có chu trình Euler: 0 0 6 6 5 5 4 4 6 3 3 5 2 2 6 1 1 0 4 3 2 2 4 1 3 0 2 1 0

Bảng 3.1 Kết quả của đồ thị Domino

3.3 Bài toán "Thanh tra giao thông"

Bài toán: Một đội tuần tra giao thông xuất phát từ trụ sở chính, họ phải tuần tra trên tất cả các con đường của một khu vực đội quản lý rồi quay trở về trụ sở. Bài toán được đưa về dạng tìm chu trình Euler với đồ thị G là khu vực quản lý, với các cạnh là những con đường, các đỉnh là các nút giao thông, đỉnh xuất phát là trụ sở chính.

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

Bản đồ khu vực quản lý mà đội thanh tra phải đi như Hình 3.4

Hình 3.4 Bản đồ khu vực thanh tra

Từ Hình 3.4 ta có đồ thị G với các đỉnh là các ngã 2, ngã 3, ngã tư và các cạnh là đường đi như Hình 3.5

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ Hình 3.5 Đồ thị biểu diễn bản đồ ở hình 3.4

Bài toán trở thành tìm 1 chu trình Euler của đồ thị G liên thông.

Rõ ràng nếu G là một đồ thị Euler (tất cả các đỉnh đều bậc chẵn) thì việc tìm hành trình của đội thanh tra chính là tìm 1 chu trình Euler. Nhưng ta nhận thấy đồ thị G có 31 đỉnh, trong đó : 23 1 2 3 4 5 8 7 6 9 10 11 13 16 17 12 14 15 19 20 21 22 25 26 27 28 24 18 29 30 31

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

- Tập đỉnh bậc chẵn V0={1, 5, 7, 10, 11, 13, 16, 17, 20, 21, 22, 23, 24, 25, 31} (15 đỉnh)

- Tập đỉnh bậc lẻ V1={2, 3, 4, 6, 8, 9, 12, 14, 15, 18, 19, 26, 27, 28, 29, 30} (16 đỉnh)

Khi đó một hành trình phải đi qua ít nhất 2 lần một số cạnh nào đó. Ta quy ước hành trình T trong đồ thị Euler GT có được bằng cách vẽ thêm một cạnh song song với mỡi cạnh mà hình trình T đi qua 2 lần là chu trình Euler cần phải tìm.

Trước hết để có được đồ thị GT là đồ thị Euler ta phải đưa tập đỉnh bậc lẻ V1 thành bậc chẵn. Công việc cần làm là phân hoạch các đỉnh trong tập V1 thành từng cặp sao cho tổng số cạnh thêm vào là ít nhất (số đường đi ngắn nhất).

Tính đường đi ngắn nhất giữa các cặp đỉnh lẻ :

Tập hợp V1 có tất cả 16 đỉnh số cặp sẽ là tổ hợp chập 2 của 16 bằng 120 Trong đó có chỉ số cặp đỉnh và Dmin là số cạnh phải nối giữa hai đỉnh

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ Cặp đỉnh 2, 3 2, 4 2, 6 2, 8 2, 9 2, 12 2, 14 2, 15 2, 18 2, 19 Dmin 1 2 2 4 3 1 3 4 2 3 Cặp đỉnh 2, 26 2, 27 2, 28 2, 29 2, 30 3, 4 3, 6 3, 8 3, 9 3, 12 Dmin 4 5 6 3 4 1 1 3 2 2 Cặp đỉnh 3, 14 3, 15 3, 18 3, 19 3, 26 3, 27 3, 28 3, 29 3, 30 4, 6 Dmin 4 5 3 4 5 6 6 4 5 2 Cặp đỉnh 4, 8 4, 9 4, 12 4, 14 4, 15 4, 18 4, 19 4, 26 4, 27 4, 28 Dmin 2 3 3 5 4 4 5 6 6 5 Cặp đỉnh 4, 29 4, 30 6, 8 6, 9 6, 12 6, 14 6, 15 6, 18 6, 19 6, 26 Dmin 5 6 2 1 3 3 4 4 3 5 Cặp đỉnh 6, 27 6, 28 6, 29 6, 30 8, 9 8, 12 8, 14 8, 15 8, 18 8, 19 Dmin 6 5 5 5 3 5 5 4 6 5 Cặp đỉnh 8, 26 8, 27 8, 28 8, 29 8, 30 9, 12 9, 14 9, 15 9, 18 9, 19 Dmin 7 6 5 7 7 2 2 3 4 2 Cặp đỉnh 9, 26 9, 27 9, 28 9, 29 9, 30 12, 14 12, 15 12, 18 12, 19 12, 26 Dmin 4 5 4 4 4 2 3 2 2 3 Cặp đỉnh 12, 27 12, 28 12, 29 12, 30 14, 15 14, 18 14, 19 14, 26 14, 27 14, 28 Dmin 4 5 2 3 1 4 2 2 3 4 Cặp đỉnh 14, 29 14, 30 15, 18 15, 19 15, 26 15, 27 15, 28 15, 29 15, 30 18, 19 Dmin 4 4 5 3 3 2 3 5 5 3 Cặp đỉnh 18, 26 18, 27 18, 28 18, 29 18, 30 19, 26 19, 27 19, 28 19, 29 19, 30 Dmin 3 4 4 1 2 2 3 4 3 2 Cặp đỉnh 26, 27 26, 28 26, 29 26, 30 27, 28 27, 29 27, 30 28, 29 28, 30 29, 30 Dmin 1 2 3 2 1 4 3 3 2 1

Bảng 3.2 Số cạnh nối thêm giữa các cặp đỉnh bậc lẻ

Từ Bảng 3.2 sử dụng phương pháp tham lam lần lượt chọn các cặp đỉnh sẽ nối có giá trị cạnh thêm là nhỏ nhất, chọn cho đến khi đủ tất cả các đỉnh bậc lẻ của đồ thị như sau :

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

STT Cặp đỉnh chọn Dmin Cạnh nối thêm

1 2, 3 1 (2, 3) 2 6, 9 1 (6, 9) 3 14 15 1 (14, 15) 4 18 29 1 (18, 29) 5 26 27 1 (26, 27) 6 4 8 2 (4, 5) ; (5, 8) 7 12 19 2 (12, 13) ; (13, 19) 8 28 30 2 (28, 31) ; (31, 30) Bảng 3.3 Cách chọn cặp đỉnh bậc lẻ và số cạnh nối thêm

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

Đồ thị GT sau khi thêm các cạnh:

Hình 3.6 Đồ thị GT có được khi thêm cạnh (các nét đứt là các cạnh nối thêm)

Khi đó đồ thị GT là một đồ thị Euler (tất cả các đỉnh đều bậc chẵn), áp dụng thuật toán Hierholzer với đỉnh xuất phát là đỉnh 3 (do trụ sở là nằm tại đỉnh 3)

23 1 2 3 4 5 8 7 6 9 10 11 13 16 17 12 14 15 19 20 21 22 25 26 27 28 24 18 29 30 31

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/ Sô đỉnh: 31 Số cạnh: 59 Số đỉnh bậc lẻ là: 0 Có chu trình Euler: 3 2 12 13 19 25 30 31 28 31 30 29 18 29 24 25 26 27 28 22 23 17 16 22 21 27 26 20 21 15 14 20 19 13 14 15 16 10 11 8 5 4 7 10 9 6 9 13 12 24 18 1 2 3 6 7 8 5 4 3

Bảng 3.4 Chu trình Euler tìm được với đồ thị GT

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

KẾT LUẬN VÀ HƢỚNG PHÁT TRIỂN Các kết quả đạt đƣợc:

Đề tài đã tìm hiểu một số thuật toán tìm chu trình Euler, cài đặt thuật toán và tổ chức lại dữ liệu để tăng tốc độ tính toán của chương trình.

Từ đó, vận dụng thuật toán vào ứng dụng cụ thể để giải quyết bài toán thanh tra giao thông. Đưa ra hành trình cho đội tuần tra một cách tốt nhất có thể.

Cài đặt chương trình so sánh tốc độ tính toán sau khi tổ chức dữ liệu với đồ thị có số đỉnh lớn.

Đề tài có tiếp tục phát triển để đem lại đáp ứng những yêu cầu thực tế.

Hƣớng phát triển của đề tài:

Cách tổ chức dữ liệu giúp tăng tốc độ tính toán, từ đó có thể áp dụng vào những ứng dụng có dữ liệu lớn, thí dụ như tìm đường đi cho các gói tin trên mạng…

Ngoài ra từ thuật toán tìm chu trình Euler cơ bản có thể áp dụng giải quyết những biến thể của bài toán, như tìm các chu trình Euler trong một đồ thị, hay tìm chu trình Euler của đồ thị con từ đó có thể giải quyết những bài toán liên quan như chuyển hàng từ kho đến các địa điểm …

Số hóa bởi Trung tâm Học liệu http://www.lrc-tnu.edu.vn/

TÀI LIỆU THAM KHẢO Tiếng Việt

[1] Kenneth H.Rosen, Toán rời rạc ứng dụng trong Tin học (Bản dịch), NXB Khoa học và Kỹ thuật, 2000.

[2] Nguyễn Đức Nghĩa, Nguyễn Tô Thành, Toán rời rạc, NXB Đại học Quốc

Một phần của tài liệu các thuật toán về đường đi và chu trình euler và ứng dụng (Trang 39 - 65)

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

(65 trang)