ĐƢỜNGĐI EULER VÀ ĐƢỜNGĐI HAMILTON

Một phần của tài liệu Bài giảng môn toán rời rạc học phần lý thuyết đồ thị (Trang 25)

7.5.1. Đường đi và chu trình EULER

Thành phố Konigsberg thuộc Phổ (bây giờ gọi là Kaliningrad thuộc Cộng hòa Nga), đƣợc chia thành bốn vùng bằng các nhánh sông Pregel. Các vùng này gồm hai vùng bên bờ sông, đảo Kneiphof và một miền nằm giữa hai nhánh của sông Pregel. Vào thế kỷ thứ 18 ngƣời ta đã xây bẩy chiếc cầu nối các vùng này với nhau. Hình 7.17. vẽ các vùng và các cầu qua sông.

D C

A

Hình 7.17. Đảo Kneiphof trên sông Pregel và 7 vhiếc cầu

Vào chủ nhật, ngƣời dân ở đây thƣờng đi bộ dọc theo các phố. Họ tự hỏi không biết có thể xuất phát tại một điểm nào đó trong thành phố, đi qua tất cả các cầu, mỗi chiếc cầu không đi qua nhiều hơn một lần, rồi lại trở về điểm xuất phát đƣợc không.

Nhà toán học Thụy sĩ, Leonard Euler, đã giải bài toán này. Lời giải của ông công bố năm 1736, có thể là một ứng dụng đầu tiên của lý thuyết đồ thị. Euler đã nghiên cứu bài toán này, mô hình hóa nó bằng một đa đồ thị, bốn

vùng đƣợc biểu diễn bằng bốn đỉnh, các cầu là các cạnh, nhƣ ở hình trên.

Bài toán tìm đƣờng đi qua tất cả các cầu mỗi cầu đi qua không quá một lần có thể đƣợc phát biểu lại bằng mô hình này nhƣ sau: Có tồn tại chu trình đơn trong đa đồ thị chứa tất cả các cạnh?

a.Định nghĩa 1. Chu trình đơn chứa tất cả các cạnh của đồ thị đƣợc gọi là chu trình Euler.

Đƣờng đi Euler trong G là đƣờng đi đơn chứa mọi cạnh của G.

Các ví dụ sau minh họa khái niệm chu trình và đƣờng đi Euler.

Ví dụ 1. Trong các đồ thị sau đây đồ thị nào có chu trình Euler? Nếu không thì liệu

nó có đƣờng đi Euler không?

f 

G1 G2 G3

Giải. Đồ thị G1 có chu trình Euler, thí dụ a,e,c,d,e,b,a. Cả hai đồ thị G2 và G3 đều không có chu trình Euler. Tuy nhiên G3 có đƣờng đi Euler, cụ thể là a,c,d,e,b,d,a,b

Một vài ghi chú về đƣờng đi và chu trình Euler:

Chu trình Euler là một đƣờng đi Euler nhƣng ngƣợc lại thì chƣa chắc đã đúng (ví dụ trên

đồ thị G3 thì a,c,d,e,b,d,a,b là đƣờng Euler, nhƣng không phải là chu trình Euler). D A C B c a b d e a b c d e a b c d e

27  Chu trình Euler có thể đi qua một đỉnh hai lần (ví dụ chu trình a,e,c,d,e,b,a trên đồ thị

G1) và có thể không đi qua một số đỉnh nào đó nếu các đỉnh này là các đỉnh cô lập, tức là các đỉnh có bậc bằng 0 (ví dụ đỉnh f trên đồ thị G1)

 Chu trình Euler chỉ liên quan đến các cạnh của đồ thị, vì vậy ta có thể thêm một số bất kỳ các đỉnh có bậc 0 (đỉnh cô lập) vào đồ thị G thì chu trình Euler của G vẫn không thay đổi.

b. Các điều kiện cần và đủ cho chu trình và đƣờng đi Euler

Định lý sau đây cho ta điều kiện cần và đủ để một đa đồ thị có chu trình Euler:

Định lý 1. Một đa đồ thị không có điểm cô lập có chu trình Euler nếu và chỉ nếu đồ thị là

liên thông và mỗi đỉnh của nó đều có bậc chẵn.

Chứng minh.

Điều kiện cần: Điều kiện liên thông khá hiển nhiên. Giả sử đồ thị liên thông G có chu trình

Euler. Chúng ta sẽ chỉ ra là tất cả các đỉnh của nó có bậc chẵn. Thật vậy giả sử chu trình Euler là a = x0, x1, ..., xn= a. Khi xuất phát từ a, chu trình góp 1 vào bậc của a, sau đó trên đƣờng đi chu trình khi tới một đỉnh thì góp thêm 1, và khi ra khỏi đỉnh lại góp thêm 1, nghĩa là mỗi lần đi qua một đỉnh chu trình lại góp thêm 2 vào bậc của các đỉnh. Khi trở về đỉnh a chu trình thêm 1 vào bậc của a. Nhƣ vậy chu trình đã cộng vào bậc của mỗi đỉnh một số chẵn. Vì chu trình đi qua tất cả các cạnh đúng một lần, do đó mỗi cạnh đã đƣợc tính thành 2 bậc (khuyên đƣợc tính là 2 bậc), góp vào các đỉnh nối chúng. Nghĩa là bằng cách tính bậc của các đỉnh thông qua chu trình, ta đã tính hết bậc của các đỉnh và của đồ thị.

Nhƣ vậy nếu đồ thị có chu trình Euler thì bậc của tất cả các đỉnh phải là số chẵn (nhƣ vậy giả thiết liên thông cho điều kiện cần là không cần thiết, vì ta có thể xem các đỉnh treo có bậc 0 cũng là các số chẵn)

Điều kiện đủ:

Giả sử G là một đồ thị liên thông và bậc của mỗi đỉnh đều là một số chẵn.

Chúng ta sẽ xây dựng một chu trình đơn C1 bắt đầu từ đỉnh a tùy ý của đồ thị. Đặt x0 = a, sau đó

chọn tùy ý các cạnh {x0,x1}, G H

{x1,x2},...,{xn-1,xn} càng dài càng tốt, sao cho x0, x1, ... , xn lập thành một chu trình. Ví dụ ở đồ thi G trên đây ta chọn các cạnh {a,f}, {f,c}, {c,b}, {b,a}.

Điều này luôn luôn làm đƣợc, vì bậc của mỗi đỉnh là một số chẵn. Xuất phát từ đỉnh a, nếu trên đƣờng chƣa gặp đỉnh a mà là một đỉnh nào đó thì đƣờng đi dùng một đƣờng để vào, và do bậc của đỉnh là chẵn nên còn một cạnh nữa để ra khỏi đỉnh này. Vì chỉ có hữu hạn điểm nên nhiều nhất là nó đi qua n-1 đỉnh còn lại để trở về a. Chu trình này có thể chứa tất cả các cạnh hoặc không. a e d f c b e d c

Nếu tất cả các cạnh đều đã đƣợc đi qua thì chu trình là chu trình Euler và thuật toán tìm chu trình Euler kết thúc.

Nếu chu trình này chƣa phải là chu trình Euler thì ta thực hiện bƣớc tiếp theo nhƣ sau:

Giả sử đồ thị ban đầu là G = (V,E). Chu trình C1 cũng là một đồ thị và C1=(V1,E1). Ta xóa khỏi đồ thị những cạnh đã có trong chu trình C1 , tức là V1. Trong số các đỉnh thuộc E1 ta xóa những đỉnh không kề với số cạnh còn lại (V2 = V \ V1). Ví dụ nhƣ trƣờng hợp trên đây thì sau khi xóa ta đƣợc đồ thị H. Đồ thị H có đỉnh c thuộc tập E1, nhƣng là đỉnh kề của các cạnh còn lại nên đƣợc giữ lại. Vì G là liên thông nên đỉnh chung nhƣ thế này luôn luôn tồn tại và có ít nhất là một. Trong trƣờng hợp tổng quát ta gọi một đỉnh chung là w. Ta thấy rằng mỗi đỉnh của H có bậc chẵn, (vì tất cả các đỉnh của G có bậc chẵn, và với mỗi đỉnh ta xóa đi từng cặp liên thuộc với nó để tạo ra H). Lƣu ý rằng H có thể là không liên thông? Bắt đầu từ w ta xây dựng chu trình C2 bằng cách chọn càng nhiều cạnh càng tốt nhƣ đã làm với G. Chẳng hạn ở hình trên là c,d,e,c. Tiếp theo ta tạo một chu trình trong G bằng cách ghép C1 và C2 (điều này làm đƣợc vì w là đỉnh chung của hai chu trình). Thực hiện điều này trên đồ thị ở hình trên ta đƣợc chu trình a,f,c,d,e,c,b,a.

Tiếo tục quá trình này cho tới khi tất cả các đỉnh đƣợc sử dụng (Quá trình này phải kết thúc vì chỉ có một số hữu hạn các cạnh trong đồ thị). Và nhƣ vậy ta đã xây dựng đƣợc chu trình Euler và điều kiện đủ đƣợc chứng minh.

Đối với đồ thị có hƣớng ta có định lý sau:

Định lý 1'. Một đa đồ thị có hƣớng không có đỉnh cô lập tồn tại chu trình Euler nếu và chỉ

nếu đồ thị là liên thông yếu đồng thời bậc-vào và bậc-ra của mỗi đỉnh là bằng nhau.

c.Thuật toán tìm chu trình Euler.

Bài toán: Cho đồ thị G = (V,E). Hãy tìm chu trình Euler của đồ thị G nếu có. Thuật toán:

 Bƣớc 1: Kiểm tra xem đồ thị có liên thông hay không. Nếu G là liên thông thì chuyển sang bƣớc 2, ngƣợc lại thì thông báo là chúng ta chỉ xét đồ thị liên thông và dừng thuật toán. (Vì có thể thấy rằng nếu đồ thị có một thành phần liên thông còn phần còn lại là các điểm cô lập thì vẫn có thể có chu trình Euler, vì chu trình Euler chỉ quan tâm đến việc đi qua các cạnh mà không quan tâm đến việc đi qua các đỉnh).

 Bƣớc 2: Kiểm tra xem tất cả các đỉnh trong G đều có bậc chẵn không. Nếu tất cả các đỉnh đều có bậc là chẵn thì chuyển sang bƣớc tiếp theo. Nếu không thì dừng lại và kết luận rằng đồ thị đã cho không có chu trình Euler.

Bƣớc 3: Xây dựng thuật toán tìm chu trình Euler đơn trong G sao cho tất cả các cạnh của G đều có chu trình đơn đi qua và chỉ đi qua một lần bằng cách sau:

1. Tạo mảng CT để ghi đƣờng đi và một Stack để xếp các đỉnh sẽ xét. Đầu tiên xếp một đỉnh u nào đó của đồ thị vào Stack, thí dụ đỉnh v1.

2. Xét đỉnh v nằm trên cùng của Stack và thực hiện:

29

 Nếu v là liên thông với đỉnh x thì đƣa x vào ngăn xếp sau đó xóa cạnh (v,x); 3. Quay lại bƣớc 2. cho tới khi ngăn xếp rỗng thì dừng. Kết quả đƣờng đi Euler đƣợc

chứa trong CE theo thứ tự ngƣợc lại.

Trong các phần tiếp theo để đơn giản, ta giả thiết các đỉnh của đồ thị là các số nguyên và đƣợc đánh số từ 1 đến n. (Với giả thiết đồ thị có n đỉnh).

Lƣu ý rằng ma trận kề của một đa đồ thị vô hƣớng không nhất thiết là ma trận 0-1. Phần tử aij của ma trận kề nhận giá trị là một số nguyên không âm bất kỳ m là số cạnh nối 2 đỉnh i và j.

Để xác định chu trình Euler của một đồ thị vô hƣớng, trƣớc hết ta cần kiểm tra xem đồ thị có liên thông không, sau đó nếu đồ thị liên thông thì kiểm tra tiếp xem bậc của các đỉnh có chẵn không. Nếu những điều kiện này thỏa mãn thì bắt đầu xây dựng chu trình Euler. Ta cũng lƣu ý là trong khi xây dựng chu trình Euler, khi có nhiều đỉnh cùng khả năng lựa chọn thì ưu

tiên chọn đỉnh có chỉ số nhỏ hơn.

Quá trình xây dựng chu trình Euler đƣợc thực hiện nhƣ sau:

Khởi tạo một Stack S chứa các phần tử là các số nguyên. Giả sử tác vụ đƣa phần tử k vào Stack là S.push(k), lấy phần tử ở đỉnh ra là S.pop(), xem phần tử ở đỉnh Stack là S.viewtop(), hàm S.empty() cho giá trị true nếu Stack rỗng, cho giá trị false nếu Stack không rỗng.

Bƣớc 0: Khởi tạo một Stack S. Ban đầu Stack rỗng, không có phần tử nào. Khởi tạo một mảng CE để chứa các đỉnh tạo nên chu trình Euler.

Bƣớc 1: Chọn một đỉnh k bất kỳ để đƣa vào Stack. Bƣớc 2: Xem phần tử h ở đỉnh Stack.

 Nếu đỉnh h có đỉnh kề (tức là trong các phần tử ahi , i=1,2,...,n có phần tử khác 0) thì chọn đỉnh kề có chỉ số nhỏ nhất để đƣa vào Stack, ví dụ là đỉnh r, đồng thời giảm các giá trị ahr và arh xuống một giá trị. Điều này có nghĩa là xóa bớt một cạnh trong số các cạnh nối đỉnh h và đỉnh r.

 Nếu đỉnh h là cô lập, tức là ahi = 0 với  i  {1,2,...,n} thì đƣa h vào mảng CE.

Bƣớc 3: Nếu Stack rỗng thì kết thúc thuật toán, nếu không thì quay lại bƣớc 2.

Ví dụ. Cho đa đồ thị vô hƣớng G = (V,E) với V = {1,2,3,4} đƣợc biểu diễn bởi ma trận kề

sau:

1 2 3 4 1 0 2 0 0 2 2 0 3 1 3 0 3 0 1

4 0 1 1 0

Hãy xây dựng một chu trình Euler cho đồ thị này nếu có thể.

Lời giải. Tính liên thông và bậc các đỉnh đều chẵn dễ dàng kiểm tra đƣợc.

Ta xây dựng chu trình Euler xuất phát từ đỉnh 1 nhƣ sau: Từ ma trận kề ta thấy

a12 = a21 = 2, a23=a32=3, a24 = a42 = 1, a34=a43=1

Các phần tử khác của ma trận kề bằng 0, do đó trong các bƣớc tiếp theo các phần tử này vẫn bằng 0 nên ta không xét đến. Ta có thể hệ thống kết quả các bƣớc trong bảng sau:

31 Bƣớc Stack CE a12, a21 a23,a32 a24,a42 A34,a43 0 2 3 1 1 1 1 2 3 1 1 2 1,2 1 3 1 1 3 1,2,1 0 3 1 1 4 1,2 1 0 3 1 1 5 1,2,3 1 0 2 1 1 6 1,2,3,2 1 0 1 1 1 7 1,2,3,2,3 1 0 0 1 1 8 1,2,3,2,3,4 1 0 0 1 0 9 1,2,3,2,3,4,2 1 0 0 0 0 10 1,2,4,3,2,3,2,1 0 0 0 0

CE đã tạo thành chu trình, tuy nhiên thứ tự ngƣợc lại nhƣ ý ta muốn. Do đó ta đảo lại chu trình này cho thuận hơn và đƣợc chu trình là 1,2,3,2,3,4,2,1.

Chƣơng trình cài đặt:

//DTCTEULE.CPP Tim chu trinh Euler trong da do thi vo huong /*Duyet do thi*/ #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <math.h> #include <dos.h> #include <assert.h> #include <iostream.h> #define true 1 #define false 0

typedef int kmatran[20][20], kvecto[20];

char *datafile="DTADJ2.DAT",*resultfile="DTCTEULE.KQ"; FILE *f;

//==================================================== int GetMatran(kmatran a,int &n);

void PutMatran(kmatran a,int n, FILE* f); void SetEqual(kmatran a, kmatran b, int n);

int LienThong(kmatran a, int n); int BacChan(kmatran a,int n);

void CTEuler(kmatran a, int n, kvecto CT, int &nCT); #include "STACK_H.CPP"

#include "ATRRLIB.CPP"

//==================================================== void main()

{// a la matran ke, d la ma tran danh sach ke, // dnum[i] la so dinh ke cua dinh i

clrscr();

kmatran a; kvecto CT;int n,i,nCT; if(!GetMatran(a,n)) return;

fcopy(datafile,resultfile); f=fopen(resultfile,"r+t"); fseek(f,0,2);//Ve cuoi tep if(!LienThong(a,n))

{printf("\nDo thi khong lien thong");getch();delay(1000);return;} if(!BacChan(a,n))

{printf("\nBac do thi khong chan");getch();delay(1000);return;} CTEuler(a,n,CT,nCT);

printf("\nChu trinh Euler la:\n");

for(i=1;i<=nCT;i++) printf("%4d",CT[i]); //fclose(f); //xemtep(resultfile); getch(); } //===================================================== int LienThong(kmatran a,int n)

{Stack<int> S(20);int i,h;kvecto chuaxet; for(i=1;i<=n;i++) chuaxet[i]=true;

S.push(1);chuaxet[1]=false; while(!S.empty())

{h=S.pop();

for(i=n;i>=1;i--)

33 }

for(i=1;i<=n;i++) if(chuaxet[i]) return(false); return(true);

}

//===================================================== int BacChan(kmatran a, int n)

{int i,j,deg; for(i=1;i<=n;i++) {deg=0; for(j=1;j<=n;j++) deg+=a[i][j]; if(deg%2) return(false); } return(true); } //==================================================== void CTEuler(kmatran a, int n, kvecto CT, int &nCT) {Stack<int> S(20);kmatran B;int i,j,h,t;

SetEqual(B,a,n);//Dat b=a de khoi phuc lai gia tri sau nay S.push(1);//Dua dinh bat ky vao Stack, o day ta chon dinh 1 nCT=0;//Ban dau chu trinh chua co phan tu nao

while(!S.empty()) {h=S.viewtop();i=1;

while(i<=n && a[h][i]==0) i++;//Tim i dau tien de a[h][i]#0

if(i==n+1) //h da la dinh co lap, dua h vao chu trinh CT {nCT++;CT[nCT]=h;S.pop();}//Lay dinh co lap ra khoi Stack else

{S.push(i);a[h][i]--;a[i][h]--;}//Loai canh (i,h) khoi do thi

}

//Dao lai chu trinh cho hop ly hon i=1;j=nCT;

while(i<j)

{t=CT[i];CT[i]=CT[j];CT[j]=t;i++;j--;} SetEqual(a,B,n);

//====================================================

Định lý 2.

Đa đồ thị liên thông có đƣờng đi Euler nhƣng không có chu trình Euler nếu và chỉ nếu nó có đùng hai đỉnh bậc lẻ.

Chứng minh. Trƣớc tiên, ta giả sử đồ thị đã cho có đƣờng đi Euler từ a đến b nhƣng không có chu trình Euler. Cạnh đầu tiên góp 1 vào deg(a). Sau đó mỗi lần đƣờng đi trở lại và đi qua đỉnh a lại góp 2 đơn vị cho deg(a). Do vậy a là một đỉnh bậc lẻ. Cạnh cuối cùng của đƣờng đi góp 1 cho deg(b) và mỗi lần đi qua b nó cũng tăng thêm 2 cho deg(b). Vì thế bậc của b là lẻ. Các đỉnh trung gian đều có bậc chẵn vì mỗi lần đƣờng đi tới rồi lại rời nó nên tăng 2 đơn vị cho bậc của nó. Vậy đồ thị đã cho có đúng 2 đỉnh bậc lẻ.

Bây giờ ta giả sử ngƣợc lại, đồ thị có đúng 2 đỉnh bậc lẻ, chẳng hạn a và b. Ta xét đồ thị rộng hơn tạo nên bằng cách thêm một cạnh nối a với b vào đồ thị xuất phát. Khi đó bậc của đồ thị mới này đều là số chẵn. Theo định lý 1, nó có chu trình Euler. Xóa cạnh mới thêm vào ta đƣợc đƣờng đi Euler của đồ thị xuất phát.

Đối với đồ thị có hƣớng ta có định lý sau:

Định lý 2'. Một đa đồ thị có hƣớng không có đỉnh cô lập tồn tại đƣờng đi Euler nhƣng không

tồn tại chu trình Euler nếu và chỉ nếu đồ thị là liên thông yếu đồng thời có 2 đỉnh, một đỉnh có bậc-vào lớn hơn bậc-ra một đơn vị, đỉnh kia có bậc-ra lớn hơn bậc-vào một đơn vị, tất cả các đỉnh còn lại có bậc-vào bằng bậc-ra.

Ví dụ 4. Đồ thị sau đây có đƣờng đi Euler không?

Giải. G có đúng 2 dỉnh bậc lẻ là b và d. Do đó nó đƣờng đi Euler nhận b và d là các điểm đầu mút. Một trong các đƣờng đi Euler là d, a, b, c, d, b.

Bây giờ trở lại bài toán cầu Konigsberg: G

Nhƣ ta thấy, đa đồ thị biểu diễn các cầu ở Konigsberg có 4 đỉnh bậc lẻ. Theo định lý 2 không có đƣờng đi Euler trong đồ thị này. Vì vậy không thể có hành trình nhƣ bài toán đặt

Một phần của tài liệu Bài giảng môn toán rời rạc học phần lý thuyết đồ thị (Trang 25)

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

(92 trang)