6. Ý nghĩa khoa học và thực tiễn của đề tài
1.3.3. Cơ chế truyền thông điệp
Các cơ chế giao tiếp trong MPI gồm có:
+ Point-to-point là cơ chế giao tiếp điểm-điểm, đây là cơ chế giao tiếp giữa từng cặp tác vụ với nhau, trong đó 1 tác vụ thực hiện công việc gửi thông điệp và tác vụ còn lại có nhiệm vụ nhận thông điệp tương ứng đó. Thông điệp được phân biệt bởi chỉ số của tác vụ và nhãn (tag) của thông điệp. Trong cơ chế này có nhiều kiểu giao tiếp với nhau, chẳng hạn như:
- Blocking: các lệnh gửi/nhận dữ liệu sẽ kết thúc khi việc gửi/nhận dữ liệu hoàn tất.
- Non-blocking: các lệnh gửi/nhận dữ liệu sẽ kết thúc ngay mà quan tâm đến việc dữ liệu đã thực sự được hoàn toàn gửi đi hoặc nhận về hay chưa. Việc dữ liệu đã thực sự được gửi đi hay nhận về sẽ được kiểm tra các lệnh khác trong thư viện MPI.
- Synchronous: gửi dữ liệu đồng bộ, quá trình gửi dữ liệu chỉ có thể được kết thúc khi quá trình nhận dữ liệu được bắt đầu.
- Buffer: một vùng nhớ đệm sẽ được tạo ra để chứa dữ liệu trước khi được gửi đi, người dùng có thể ghi đè lên vùng bộ nhớ chứa dữ liệu mà không sợ làm mất dữ
liệu chuẩn bị gửi.
- Ready: quá trình gửi dữ liệu chỉ có thể được bắt đầu khi quá trình nhận dữ liệu đã sẵn sàng.
Bảng dưới đây tổng hợp các chế độ giao tiếp điểm-điểm và các lệnh thông điệp tương ứng, thông tin chi tiết về các lệnh này sẽ được trình bày ở những phần sau:
Bảng 1.2. Cơ chế giao tiếp Point-to-point
Chế độ Điều kiện kết thúc Blocking Non-Blocking
Send Thông điệp đã được gửi MPI_Send MPI_Isend
Receive Thông điệp đã được nhận MPI_Recv MPI_Irecv Synchronous send Khi quá trình nhận bắt đầu MPI_Ssend MPI_Issend
Buffer send Luôn kết thúc, không quan tâm quá trình nhận đã bắt đầu hay chưa
MPI_Bsend MPI_Ibsend
Ready send Luôn kết thúc, không quan tâm quá trình nhận đã kết thúc hay chưa
MPI_Rsend MPI_Irsend
+ Collective communication là cơ chế giao tiếp tập thể, liên quan tới tất cả các tác vụ nằm trong phạm vi của communicator, các kiểu giao tiếp trong cơ chế này gồm có:
- Broadcast : dữ liệu giống nhau được gửi từ tác vụ gốc (root) đến tất cả các tác vụ khác trong communicator.
- Scatter : các dữ liệu khác nhau được gửi từ tác vụ gốc đến tất cả các tác vụ khác trong communicator.
- Gather : các dữ liệu khác nhau được thu thập bởi tác vụ gốc từ tất cả các tác vụ khác trong communicator.
- Reduce : phương thức này cho phép ta có thể thu thập dữ liệu từ mỗi tác vụ, rút gọn dữ liệu, lưu trữ dữ liệu vào trong một tác vụ gốc hoặc trong tất cả các tác vụ.
gather reduction
Hình 1.12. Cơ chế giao tiếp tập thể 1.3.4. Các lệnh truyền thông điệp blocking
Một số lệnh thông dụng cho chế độ truyền thông điệp blocking gồm có:
- MPI Send gửi các thông tin cơ bản
MPI_Send(&buf,count,datatype,dest,tag,comm) Comm::Send(&buf,count,datatype,dest,tag)
- MPI Recv nhận các thông tin cơ bản
MPI_Recv(&buf,count,datatype,source,tag,comm,&status) Comm::Recv(&buf,count,datatype,source,tag,status)
- MPI Ssend gửi đồng bộ thông tin, lệnh này sẽ chờ cho đến khi thông tin đã được nhận (thông tin được gửi sẽ bị giữ lại cho đến khi bộ đệm của tác vụ gửi được giải phóng để có thể sử dụng lại và tác vụ đích (destination process) bắt đầu nhận thông tin)
MPI_Ssend (&buf,count,datatype,dest,tag,comm) Comm::Ssend(&buf,count,datatype,dest,tag)
- MPI Bsend tạo một bộ nhớ đệm (buffer) mà dữ liệu được lưu vào cho đến khi được gửi đi, lệnh này sẽ kết thúc khi hoàn tất việc lưu dữ liệu vào bộ nhớ đệm.
MPI_Bsend (&buf,count,datatype,dest,tag,comm) Comm::Bsend(&buf,count,datatype,dest,tag)
- MPI Buffer attach cấp phát dung lượng bộ nhớ đệm cho thông tin được sử dụng bởi lệnh MPI_Bsend()
MPI_Buffer_attach (&buffer,size) Attach_buffer(&buffer,size)
bởi lệnh MPI_Bsend()
MPI_Buffer_detach (&buffer,size) Detach_buffer(&buffer,size)
- MPI Rsend gửi thông tin theo chế độ ready, chỉ nên sử dụng khi người lập trình chắc chắn rằng quá trình nhận thông tin đã sẵn sàng.
MPI_Rsend (&buf,count,datatype,dest,tag,comm) Comm::Rsend(&buf,count,datatype,dest,tag)
- MPI Sendrecv gửi thông tin đi và sẵn sàng cho việc nhận thông tin từ tác vụ khác MPI_Sendrecv (&sendbuf,sendcount,sendtype,dest,sendtag,
&recvbuf,recvcount,recvtype,source,recvtag,comm,&status) Comm::Sendrecv(&sendbuf,sendcount,sendtype,dest,sendtag, &recvbuf,recvcount,recvtype,source,recvtag,status)
- MPI Wait chờ cho đến khi các tác vụ gửi và nhận thông tin đã hoàn thành MPI_Wait (&request,&status)
Request::Wait(status)
- MPI Probe kiểm tra tính blocking của thông tin
MPI_Probe (source,tag,comm,&status) Comm::Probe(source,tag,status)
Ví dụ:
# include <stdio.h> # include <mpi.h>
int main(int argc, char **argv) {
int numtasks, rank, dest, source, rc , count, tag = 1; char inmsg, outmsg= 'x ' ; MPI_Status Stat;
MPI_Init (&argc ,&argv) ;
MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { dest = 1; source = 1 ;
rc = MPI_Send (&outmsg, 1,MPI_CHAR,dest,tag, MPI_COMM_WORLD);
rc = MPI_Recv(&inmsg,1,MPI_CHAR, source, tag ,MPI_COMM_WORLD, & Stat); } else if (rank == 1) { dest = 0 ; source = 0;
rc = MPI_Recv(&inmsg,1,MPI_CHAR, source, tag, MPI_COMM_WORLD, & Stat ) ;
rc = MPI_Send(&outmsg,1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); }
printf ("Task %d : Received %d char(s) from task %d with tag %d \n" , rank, count, Stat.MPI_SOURCE, Stat.MPI_TAG);
MPI_Finalize() ; }
- Kết quả: Thực hiện truyền thông có khóa gửi message ‘x’, ‘y’ từ tác vụ có id = 0 tới tác vụ id = ‘1’
1.3.5. Các lệnh truyền thông điệp non-blocking
Một số lệnh thông dụng cho chế độ truyền thông điệp non-blocking gồm có: MPI Isend gửi thông điệp non-blocking, xác định một khu vực của bộ nhớ thực hiện nhiệm vụ như là một bộ đệm gửi thông tin.
MPI_Isend (&buf,count,datatype,dest,tag,comm,&request) Request Comm::Isend(&buf,count,datatype,dest,tag)
- MPI Irecv nhận thông điệp non-blocking, xác định một khu vực của bộ nhớ thực hiện nhiệm vụ như là một bộ đệm nhận thông tin.
MPI_Irecv (&buf,count,datatype,source,tag,comm,&request) Request Comm::Irecv(&buf,count,datatype,source,tag) - MPI Issend gửi thông điệp non-blocking đồng bộ (synchronous).
MPI_Issend (&buf,count,datatype,dest,tag,comm,&request) Request Comm::Issend(&buf,count,datatype,dest,tag) - MPI Ibsend gửi thông điệp non-blocking theo cơ chế buffer.
MPI_Ibsend (&buf,count,datatype,dest,tag,comm,&request) Request Comm::Ibsend(&buf,count,datatype,dest,tag) - MPI Irsend gửi thông điệp non-blocking theo cơ chế ready.
MPI_Irsend (&buf,count,datatype,dest,tag,comm,&request) Request Comm::Irsend(&buf,count,datatype,dest,tag)
- MPI Test kiểm tra trạng thái kết thúc của các lệnh gửi và nhận thông điệp non- blocking Isend(), Irecv(). Tham số request là tên biến yêu cầu đã được dùng trong các lệnh gửi và nhận thông điệp, tham số flag sẽ trả về giá trị 1 nếu thao tác hoàn thành và giá trị 0 trong trường hợp ngược lại.
MPI_Test (&request,&flag,&status) Request::Test(status)
- MPI Iprobe kiểm tra tính non-blocking của thông điệp
MPI_Iprobe(source,tag,comm,&flag,&status) Comm::Iprobe(source,tag,status)
Ví dụ:
#include <stdio.h> #include <mpi.h>
int main (int argc, char **argv) {
int numtasks, rank, next, prev, buf [2], tagl = 1, tag2 = 2; MPI_Request reqs [4];
MPI_Status stats [2]; MPI_Init (&argc, &argv) ;
MPI_Comm_size (MPI_COMM_WORLD, &numtasks); MPI_Comm_rank (MPI_COMM_WORLD, &rank); prev = rank - 1; next = rank + 1;
if (rank == 0) prev = numtasks - 1; if (rank == (numtasks - 1)) next = 0; MPI_Irecv (&buf [0], 1, MPI_INT, prev, tagl, MPI_COMM_WORLD, &reqs[0]); MPI_Irecv(&buf [1 ], 1, MPI_INT, next, tag2, MPI_COMM_WORLD, &reqs[1 ]); MPI_Isend (&rank,1,MPI_INT, prev, tag2, MPI_COMM_WORLD, &reqs [2]); MPI_Isend (&rank, 1, MPI_INT, next, tagl, MPI_COMM_WORLD, &reqs [3 ]); { /* do some work */ }
MPI_Waitall (4, reqs, stats); MPI_Finalize ();
}
- Kết quả: Đoạn code trên thực hiện gửi message vòng tròn từ giữa các tác vụ, ví dụ tác vụ có id là i gửi dữ liệu tới tác vụ có id là i +1 và ngược lại.
1.3.6. Các lệnh truyền thông tập thể
Một số lệnh thông dụng cho cơ chế truyền thông tập thể gồm có:
- MPI Barrier lệnh đồng bộ hóa (rào chắn), tác vụ tại rào chắn (barrier) phải chờ cho đến khi tất cả các tác vụ khác trên cùng một communicator đều hoàn thành.
MPI_Barrier (comm) Intracomm::Barrier()
- MPI Bcast gửi bản sao của bộ đệm có kích thước count từ tác vụ root đến tất cả các tiến trình khác trong cùng một communicator.
MPI_Bcast (&buffer,count,datatype,root,comm) Intracomm::Bcast(&buffer,count,datatype,root)
- MPI Scatter phân phát giá trị bộ đệm lên tất cả các tác vụ khác, bộ đệm được chia thành sendcnt phần.
MPI_Scatter(&sendbuf,sendcnt,sendtype,&recvbuf,recvcnt,recvtype,root, comm)
Intracomm::Scatter(&sendbuf,sendcnt,sendtype,&recvbuf,recvcnt,recvtype, root)
- MPI Gather tạo mới một giá trị bộ đệm riêng cho mình từ các mảnh dữ liệu gộp lại. MPI_Gather(&sendbuf,sendcnt,sendtype,&recvbuf,recvcnt,recvtype,root, comm)
Intracomm::Gather(&sendbuf,sendcnt,sendtype,&recvbuf,recvcnt,recvtype, root)
- MPI Allgather tương tự như MPI_GATHER nhưng sao chép bộ đệm mới cho tất cả các tác vụ.
MPI_Allgather(&sendbuf,sendcnt,sendtype,&recvbuf,recvcount,recvtype, comm)
Intracomm::Allgather(&sendbuf,sendcnt,sendtype,&recvbuf,recvcnt,recvtype) - MPI _ Reduce áp dụng các toán tử rút gọn (tham số op) cho tất cả các tác vụ và lưu kết quả vào một tác vụ duy nhất.
MPI_Reduce (&sendbuf,&recvbuf,count,datatype,op,root,comm) Intracomm::Reduce(&sendbuf,&recvbuf,count,datatype,op,root)
- Các toán tử rút gọn gồm có: MPI_MAX (cực đại), MPI_MIN (cực tiểu), MPI_SUM (tổng), MPI_PROD (tích), MPI_LAND (toán tử AND logic), MPI_BAND (toán tử AND bitwise), MPI_LOR (toán tử OR logic), MPI_BOR (toán tử OR bitwise), MPI_LXOR (toán tử XOR logic), MPI_BXOR (toán tử XOR bitwise), MPI_MAXLOC (giá tri cực đại và vi trí), MPI_MINLOC (giá tri cực tiểu và vi trí). - MPI Allreduce tương tự như MPI_Reduce nhưng lưu kết quả vào tất cả các tác vụ.
MPI_Allreduce(&sendbuf,&recvbuf,count, datatype,op,comm) Intracomm::Allreduce(&sendbuf,&recvbuf,count, datatype,op)
- MPI Reduce scatter tương đương với việc áp dụng lệnh MPI_Reduce rồi tới lệnh MPI_Scatter.
MPI_Reduce_scatter(&sendbuf,&recvbuf,recvcount,datatype,op,comm) Intracomm::Reduce_scatter(&sendbuf,&recvbuf,recvcount[], datatype,op)
- MPI Alltoall tương đương với việc áp dụng lệnh MPI_Scatter rồi tới lệnh MPI_Gather.
MPI_Alltoall(&sendbuf,sendcount,sendtype,&recvbuf,recvcnt,recvtype, comm)
Intracomm::Alltoall(&sendbuf,sendcount,sendtype,&recvbuf,recvcnt, recvtype)
- MPI Scan kiểm tra việc thực hiện toán tử rút gọn của các tác vụ. MPI_Scan(&sendbuf,&recvbuf,count,datatype,op,comm) Intracomm::Scan(&sendbuf,&recvbuf,count, datatype,op) Ví dụ: #include "mpi.h" #include "stdio.h" #define SIZE 4
int main (int argc, char* argv[] ) {
int numtasks, rank, sendcount, recvcount, source; float sendbuf [SIZE][SIZE] = {
{1.0, 2.0, 3.0, 4.0}, {5.0, 6.0, 7.0, 8.0}, {9.0, 10.0, 11.0, 12.0}, {13.0, 14.0, 15.0, 16.0} }; float recvbuf [SIZE]; //Khoi tao moi truong MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &rank); MPI_Comm_size (MPI_COMM_WORLD, &numtasks); if (numtasks == SIZE)
{
source = 1;
sendcount = SIZE; recvcount = SIZE;
//Gui du lieu tu tac vu co id = 1 toi cac tac vu khac
MPI_Scatter(sendbuf,sendcount,MPI_FLOAT,recvbuf,recvcount, MPI_FLOAT,source,MPI_COMM_WORLD);
//In ra du lieu trong cac tac vu
printf("Id task= %d ket qua: %f %f %f %f\n",
rank, recvbuf[0], recvbuf[1],recvbuf[2],recvbuf[3]); }
else printf("So tac su dung nen bang: %d. Ket thuc.\n",SIZE); MPI_Finalize();
}
1.4. Kết luận chương
Để giải những bài toán đặt ra một cách hiệu quả trên những máy tính mà chúng ta có, vấn đề chính là làm thế nào để xây dựng được những thuật toán song song. Cách làm khá thông dụng là biến đổi các thuật toán tuần tự về song song, hay chuyển từ một dạng song song về dạng song song phù hợp hơn nhưng vẫn bảo toàn được tính tương đương trong tính toán.
Dựa vào bốn công đoạn và những nguyên lý thiết kế chính: nguyên lý lập lịch, nguyên lý hình ống, nguyên lý chia để trị, nguyên lý đồ thị phụ thuộc dữ liệu, nguyên lý điều kiện tranh đua để xây dựng một số thuật toán song song.
Để đánh giá được tính hiệu quả của thuật toán song song thường phải dựa vào độ phức tạp thời gian của thuật toán. Độ phức tạp thời gian của thuật toán song song không chỉ phụ thuộc vào kích cỡ của dữ liệu đầu vào mà còn phụ thuộc vào kiến trúc máy tính song song và số lượng các bộ xử lý được phép sử dụng trong hệ thống.
CHƯƠNG 2
CÁC THUẬT TOÁN TRÊN ĐỒ THỊ
2.1.Thuật toán Dijkstra tìm đường đi ngắn nhất
2.1.1.Mô tả thuật toán
Thuật toán Dijkstra [3], mang tên của nhà khoa học máy tính người Hà Lan Edsger Dijkstra, là một thuật toán giải quyết bài toán tìm đường đi ngắn nhất nguồn đơn trong một đồ thị có hướng không có cạnh mang trọng số âm.
Phát biểu bài toán: Cho đơn đồ thị liên thông, có trọng số G=(V,E). Tìm khoảng cách d(u0,v) từ một đỉnh u0 cho trước đến một đỉnh v bất kỳ của G và tìm đường đi ngắn nhất từ u0 đến v.
Phương pháp của thuật toán Dijkstra là: xác định tuần tự đỉnh có khoảng cách đến u0 từ nhỏ đến lớn.
Trước tiên, đỉnh có khoảng cách đến a nhỏ nhất chính là a, với d(u0,u0)=0. Trong các đỉnh v # u0, tìm đỉnh có khoảng cách k1 đến u0 là nhỏ nhất. Đỉnh này phải là một trong các đỉnh kề với u0. Giả sử đó là u1:
d(u0,u1) = k1
Trong các đỉnh v # u0 và v # u1, tìm đỉnh có khoảng cách k2 đến u0 là nhỏ nhất. Đỉnh này phải là một trong các đỉnh kề với u0 hoặc với u1. Giả sử đó là u2:
d(u0,u2) = k2
Tiếp tục như trên, cho đến bao giờ tìm được khoảng cách từ u0 đến mọi đỉnh v của G. Nếu V={u0, u1,…, un} thì:
0 = d(u0,u0) < d(u0,u1) < d(u0,u2) < … < d(u0,un). Thuật toán Dijkstra :
+ Đầu vào: Đồ thị liên thông G(V,E,w), w(i,j) > 0 (i,j) E, đỉnh nguồn a. + Đầu ra : Chiều dài đường đi ngắn nhất và đường đi ngắn nhất từ đỉnh a đến các đỉnh của đồ thị.
+ Phương pháp :
Bước 1: Gán L(a):= 0. Với mọi đỉnh x a gán L(x) = . Đặt T:=V.
Bước 2: Chọn v T, v chưa xét sao cho L(v) có giá trị nhỏ nhất. Đặt T := T - {v}, đánh dấu đỉnh v đã xét.
Bước 3: Nếu T= , kết thúc. L(z), z V, z a là chiều dài đường đi ngắn nhất từ a đến z. Từ z lần ngược theo đỉnh được ghi nhớ ta có đường đi ngắn nhất. (L(z) không thay đổi, nếu L(z) = thì không tồn tại đường đi.
Ngược lại sang bước 4.
thay đổi thì ghi nhớ đỉnh v cạnh đỉnh x bằng mảng truoc[] (với truoc[] của đỉnh 1 = 0) để sau này xây dựng đường đi ngắn nhất.
Quay về bước 2.
Độ phức tạp của thuật toán Dijkstra: Thuật toán dùng không quá n-1 bước lặp. Trong mỗi bước lặp, dùng không hơn 2(n-1) phép cộng và phép so sánh để sửa đỗi nhãn của các đỉnh. Ngoài ra, một đỉnh thuộc Sk có nhãn nhỏ nhất nhờ không quá n – 1 phép so sánh. Do đó thuật toán có độ phức tạp O(n2
).
2.1.2.Ví dụ minh họa
Dùng thuật toán Dijkstra, tìm đường đi ngắn nhất từ a đến z trong đồ thị sau:
+ Ta có: V = {a,b,c,d,e,z}; S =
+ Bước 1: ta gán 0 cho đỉnh a và gán cho các đỉnh còn lại. L(a) = 0.
+ Trong các đỉnh không thuộc S = {a} và kề với a có 2 đỉnh b,c. Ta có: L(b) = min {∞, L(a) + w(ab)} = min {∞, 0 + 4} = 4.
L(c) = min {∞, L(a) + w(ac)} = min {∞, 0 + 2} = 2. Ta có: L(c) nhỏ nhất nên c S, S = {a, c}.
+ Trong các đỉnh không thuộc S mà kề với c có 3 đỉnh b, d, e. Ta có: L(b) = min {4, L(c) + w(cb)} = min{4,2+1} = 3.
L(e) = min {∞, L(c) + w(ce)} = min{∞,12} = 12. L(d) = min{∞,L(c) + w(cd)} = min{∞,2 + 8} = 10. Ta có: L(b) nhỏ nhất nên b S, S = {a, b, c}.
+ Trong các đỉnh không thuộc S mà kề với b có đỉnh d. Ta có: L(d) = min {10, L(b) + w(bd)} = min {10, 3 + 5} = 8.
d S, S = {a, b, c, d}
+ Trong các đỉnh không thuộc S mà kề với d có đỉnh e, z. Ta có: L(e) = min {12, L(d) + w(de)} = min{12, 2+8} = 10.
L(z) = min {∞, L(d) + w(dz)} = min{∞, 8+6} = 14. Ta có: L(e) nhỏ nhất nên e S, S = {a, b, c, d, e}.
+ Trong các đỉnh không thuộc S mà kề với e có đỉnh z. Ta có: L(z) = min {14, L(e) + w(ez)} = min{14, 10+3} = 13.
Ví dụ 2: Cho đồ thị được biểu diễn sau đây, sau khi thuật toán thực hiện xong thì kết quả được ghi nhớ lên các nhãn đỉnh tương ứng.
Hình 2.1. Ghi nhớ kết quả tính được trên đồ thị
Mảng truoc[]=0 1 1 2 3 3 6 4 8 11 7 11 (Mảng ghi nhớ truoc [] dùng để tìm đường đi, với truoc[1]=0)
Mảng độ dài L = 0 7 5 13 15 15 17 18 38 39 24 29 Vậy kết quả từ đỉnh 1 đến tất cả các đỉnh là: đến 2=7 (12) đến 3=5 (13) đến 4=13 (124) đến 5=15 (135) đến 6=15 (136) đến 7=17 (1367) đến 8=18 (1248) đến 9=38 (1248) đến 10=39 (13671110) đến 11= 24 (136711) đến 12=29 (13671112) (0) (7)1 (5)1 (13)2 (15)3 (15)3 (17)6 (24)7 (18)4 (38)8 (39)11 1 2 3 4 7 4 7 5 6 1 11 5 7 6 8 11 9 10 0 15 20 6 7 10 2 20 10 10 6 4 5 18 10 15 12 5 (29) 11
2.2.Thuật toán tuần tự Prim tìm cây khung cực tiểu
2.2.1.Mô tả thuật toán
Đầu vào: Đồ thị G=(V,E) với trọng số. Các đỉnh ký hiệu là 1,2,3,…,n
Trọng số của cạnh (i,j), (i,j)E, ký hiệu là cij, đỉnh nguồn a, 1 bộ xử lý chính và m-1 bộ xử lý phụ.
Đầu ra: Cây phủ nhỏ nhất T, Hoặc kết luận đồ thị không liên thông. Các bước:
(1) Khởi tạo: T là đồ thị gồm một đỉnh 1 và không có cạnh
(2) Kiểm tra điều kiện kết thúc:
Nếu T có n-1 cạnh, kết thúc, kết luận: T là cây phủ nhỏ nhất. Ngược lại sang bước (3)
(3) Thêm cạnh:
Ký hiệu M là tập M ={ (i,j)E| iT&jT} Tìm cạnh (k,h)M sao cho :
ckh=min{cij|(i,j)M }
Nếu ckh<∞, thêm cạnh (k,h) và đỉnh h vào T, sang bước (2). Ngược lại tức M= , kết thúc. Kết luận đồ thị G không liên thông
2.2.2.Ví dụ minh họa
Tìm cây phủ nhỏ nhất của đồ thị
(1) Khởi tạo: T chỉ có đỉnh a không có cạnh T:= ({a},), d(T):=0
(2) Kiểm tra: Số cạnh của T là 0, sang bước (3)
(3) Thêm cạnh: tập M={(a,e),(a,c),(a,b)} Ta có cac=2=min{cij|(i,j)M }
Thêm đỉnh c và cạnh (a,c) vào T, T:= ({a,c},{(a,c)}), d(T):=d(T)+ cac=2
(2) Kiểm tra: Số cạnh của T là 1, sang bước (3)
(3) Thêm cạnh: tập M={(a,e),(a,b),(c,e),(c,f),(c,d)} Ta có ccd=1=min{cij|(i,j)M }
Thêm đỉnh d và cạnh (c,d) vào T, T:= ({a,c,d},{(a,c),(c,d)}), d(T):=d(T)+ ccd=2+1=3 a b d c e f 4 3 3 5 2 2 6 1 6
(2) Kiểm tra: Số cạnh của T là 2, sang bước (3)
(3) Thêm cạnh: tập M={(a,e),(a,b),(c,e),(c,f),(d,b),(d,f)} Ta có cae=3=min{cij|(i,j)M }
Thêm đỉnh e và cạnh (a,e) vào T, T:= ({a,c,d,e},{(a,c),(c,d),(a,e)}), d(T):=d(T)+ cae=3+3=6
(2) Kiểm tra: Số cạnh của T là 3, sang bước (3)
(3) Thêm cạnh: tập M={(a,b),(c,f),(d,b),(d,f),(e,f)}Ta có cef=2=min{cij|(i,j)M
}
Thêm đỉnh f và cạnh (e,f) vào T,
T:= ({a,c,d,e,f},{(a,c),(c,d),(a,e),(e,f)}), d(T):=d(T)+ cef=6+2=8
(2) Kiểm tra: Số cạnh của T là 4, sang bước (3)
(3) Thêm cạnh: tập M={(a,b),(d,b)}Ta có cab=4=min{cij|(i,j)M }
Thêm đỉnh b và cạnh (a,b) vào T, T:=
({a,c,d,e,f,b},{(a,c),(c,d),(a,e),(e,f),(a,b)}), d(T):=d(T)+ cab=8+4=12
(2) Kiểm tra: Số cạnh của T là 5, kết thúc.
Kết luận: Ta có cây phủ nhỏ nhất gồm các cạnh: (a,c),(c,d),(a,e),(e,f),(a,b)
Với tổng trọng số là: d(T):=2+1+3+2+4=12 a b d c e f 4 3 3 5 2 2 6 1 6
CHƯƠNG 3
NGHIÊN CỨU ỨNG DỤNG THUẬT TOÁN SONG SONG