You are on page 1of 25

Data Structures and

Algorithms

Graphs

NGUYỄN THỊ MAI CHI - 22029047


PHÙNG TUẤN KIỆT - 22029008
THIỀU VIỆT TUẤN KHANH - 22029024
NGYỄN CÔNG HUY- 22029027
PHẠM MẠNH KIÊN - 22029093
NGÔ TUẤN HƯNG - 22029032
MỤC LỤC
I KHÁI NIỆM

II BIỂU DIỄ N ĐỒ THỊ

III KỸ THUẬT DUYỆT ĐỒ THỊ


I. KHÁI NIỆM
1.ĐỒ THỊ
Đồ thị là một cặp (V, E), trong đó :
-V là tập các đỉnh(nodes/vertices)
-E là một tập các cặp đỉnh(tập các cạnh)
Ví dụ:
2.ỨNG DỤNG

Các bản mạch điện


Các mạng vận tải
-Mạng lưới đường cao tốc
-Mạng lưới máy bay
Các mạng máy tính
-Mạng cục bộ
-Mạng internet
-Web
Cơ sở dữ liệu
-Lược đồ quan hệ thực thể
3. CÁC LOẠI CẠNH
Cạnh có hướng
- Cặp đỉnh có thứ tự (u,v)
-u là đỉnh đầu
-v là đỉnh cuối
-Ví dụ: một chuyến bay
Cạnh vô hướng
-Cặp đỉnh không có thứ tự (u,v)
-Ví dụ: Đường bay
Đồ thị có hướng
-Tất cả các cạnh có hướng
Đồ thị vô hướng
-Tất cả các cạnh là vô hướng
4.CÁC THUẬT NGỮ
Đỉnh kết thúc
-U và V là các điểm kết thức
Các cạnh kề với một đỉnh
-a, d, và b kề với đỉnh V
Các đỉnh kề nhau
-U và V là hai đỉnh kề nhau
Bậc của một đỉnh
-X có bậc bằng 5
Các cạnh song song
-h và i là hai cạnh song song
Cạnh tự lặp (khuyên)
-j là cạnh tự lặp
Đường đi
-Là một dãy các cạnh và đỉnh xen kẽ nhau.
-Bắt đầu tại một đỉnh
-Kết thúc tại một đỉnh
-Mỗi cạnh nằm giữa hai đỉnh kết thức của nó.
Đường đi đơn
-Là đường đi mà các đỉnh và các cạnh của nó là khác nhau.
Ví dụ:
-P1=(V,b,X,h,Z) là đường đi đơn
-P2=(U,c,W,e,X,g,Y,f,W,d,V) Không phải là đường đi đơn
Chu trình
-Là một đường đi khép kín
Chu trình đơn
-Là đường đi đơn khép kín
Ví dụ
-C1=(V,b,X,g,Y,f,W,c,U,a,) là chu trình đơn
-C2=(U,c,W,e,X,g,Y,f,W,d,V,a,) không phải là chu trình đơn
II, Biểu diễn
I. Biểu diễn đồ thị bằng ma trận kề
- Xét đồ thị G(V, E), V là tập các đỉnh (n≥1), E là tập các cạnh/cung ( tập các
cặp (u, v) mà u, v là hai đỉnh thuộc V.
- Giả sử các đỉnh được đánh số thứ tự theo một quy định nào đó.
- Ma trận A biểu diễn đồ thị G gồm n đỉnh là một ma trận vuông (mảng 2
chiều) kích thước nxn. Các phần tử của ma trận đó có giá trị 0 hoặc 1.
- Aij= 0 nếu không tồn tại cung (, ) trong E.
- Aij= 1 nếu tồn tại cung (, ) trong E.
NHẬN XÉT
*Nếu đồ thị vô hướng thì ma trận A đối
xứng qua đường chéo chính ( = )
*Với đồ thị có trọng số thì ma trận kề
thay giá trị 1 bằng trọng số tương ứng
của cung đó.
*Nếu đồ thị có trọng số thì chúng ta thay
a[u][v]=1 và a[v][u]=1 đó thành a[u][v] =
a[v][u] = C (Với C chính là trọng số của
cạnh đó).
*Nếu đồ thị có hướng, và dữ liệu đề bài
nói rõ cạnh đi từ u đến v thì ta chỉ gán
a[u][v] = 1 và không gán chiều ngược lại.
II. Biểu diễn đồ thị bằng danh sách các đỉnh kề

- Dùng mảng 1 chiều G có n phần tử để biểu diễn cho đồ thi có n đỉnh


- G[i] là con trỏ trỏ tới danh sách các đỉnh kề với đỉnh i
- Các đỉnh kề với một đỉnh i trong một danh sách sẽ liên kết theo một thứ tự nào
đó
Do danh sách kề là mảng của các danh sách liên kết, nên chúng ta cần định nghĩa
cấu trúc Node cho các phần tử của danh sách liên kết:
Ngoài ra, chúng ta cũng cần định nghĩa cấu trúc đồ thị: mảng của các danh sách liên
kết với số lượng đỉnh cho trước:
III.Kỹ thuật duyệt đồ thị (Graph traversal)
1.KHÁI NIỆM

- Duyệt đồ thị (hay còn gọi là đi qua đồ thị) có nghĩa là ta cần “thăm” tất cả các
đỉnh và cung của đồ thị theo một trật tự nào đó. Giải quyết nhiều vấn đề của lý
thuyết đồ thị đòi hỏi ta cần phải duyệt đồ thị. Vì vậy, các kỹ thuật đi qua đồ thị
đóng vai trò quan trọng trong việc thiết kế các thuật toán đồ thị.

- Chẳng hạn, bằng cách duyệt đồ thị, ta có thể đưa ra thuật giải cho các vấn đề: đồ
thị có chu trình hay không? Đồ thị có liên thông không? Từ đỉnh u bất kỳ ta có thể
đi tới đỉnh v bất kỳ khác hay không?

- Có hai kỹ thuật duyệt đồ thị: duyệt đồ thị theo bề rộng và duyệt đồ thị theo độ
sâu.
1. Tìm kiếm theo chiều sâu (Depth-first search)

a) Tìm kiếm theo chiều sâu (Depth-first search - DFS)

- là một kỹ thuật duyệt đồ thị cơ bản. Thuật toán bắt đầu tại một node, và
tiếp tục đi đến các node khác từ node bắt đầu bằng các cạnh của đồ thị.

-Tìm kiếm theo chiều sâu luôn theo một con đường duy nhất trong đồ thị
để tìm các node mới. Sau đó, nó quay lại node liền trước và bắt đầu khai
phá các con đường khác của đồ thị. Thuật toán lưu trữ các node đã duyệt,
để nó đi đến mỗi node một lần duy nhất.
b) Ví dụ
Chúng ta xem xét cách tìm kiếm theo chiều sâu xử lý đồ thị sau:

Chúng ta có thể bắt đầu tìm kiếm tại một


node bất kỳ của đồ thị; bây giờ chúng ta bắt
đầu việc tìm kiếm tại node 1.

Đầu tiên, việc tìm kiếm di chuyển đến node 2:

Sau đó, nodes 3 và 5 sẽ được duyệt:


Các node kề của node 5 là 2 và 3, nhưng việc tìm kiếm đã vừa duyệt các nodes này, vì thế nó quay
ngược lại các nodes trước đó. Cũng tương tự tất cả các nodes kề của 3 và 2 đều đã được duyệt, vì thế
tiếp theo chúng ta di chuyển từ node 1 đến node 4.

Sau đó, việc tìm kiếm kết thúc vì tất cả các nodes đã được duyệt.
Độ phức tạp thời gian của tìm kiếm theo chiều sâu là O(n + m) khi n là số lượng đỉnh và m là
số lượng cạnh, vì thuật toán xử lý mỗi đỉnh và mỗi cạnh.
c) Thực thi mã

Tìm kiếm theo chiều sâu có thể được thực thi một cách tiện lợi bằng đệ quy. Hàm dfs sau bắt
đầu một tìm kiếm theo chiều sâu tại một đỉnh xác định. Hàm giả thiết rằng đồ thị được lưu trữ
theo danh sách kề trong một mảng:

vector<int> adj[N];

và cũng duy trì một mảng:

bool visited[N];
để lưu vết các đỉnh đã viếng thăm. Khởi tạo, mỗi giá trị của mảng là false, và khi
việc tìm kiếm bắt đầu từ đỉnh s, giá trị của visited[s] thành true. Hàm có thể được
thực thi như sau:

void dfs(s) {
if (visited[s]) return;
visited[s] = true;
// process node s
for(auto u : adj[s]) {
dfs(u);
}
}
1. Tìm kiếm theo chiều rộng (Breadth-first search)

a) Tìm kiếm theo chiều rộng (Breadth-first search - BFS)


Duyệt các đỉnh theo thứ tự tăng dần theo khoảng cách từ chúng đến
đỉnh bắt đầu. Vì thế, chúng ta có thể tính toán khoảng cách từ đỉnh
bắt đầu đến tất cả các đỉnh khác bằng tìm kiếm theo chiều rộng. Tuy
nhiên, tìm kiếm theo chiều rộng thì khó thực thi hơn tìm kiếm theo
chiều sâu.

Tìm kiếm theo chiều rộng đi qua các đỉnh cấp 1 sau đó mới đến các
đỉnh khác. Đầu tiên, thuật toán tìm kiếm khai phá các đỉnh mà có
khoảng cách đến đỉnh bắt đầu là 1, sau đó các đỉnh có khoảng cách là
2, v.v… Quá trình này được tiếp tục cho đến khi tất cả các đỉnh đã
được duyệt.
b) Ví dụ
Chúng ta cùng xem xét cách tìm kiếm theo chiều rộng xử lý đồ thị sau:

Giả thiết rằng việc tìm kiếm bắt đầu tại đỉnh 1.
Đầu tiên, chúng ta xử lý tất cả các đỉnh có thể đi
đến từ đỉnh 1 bằng một cạnh:

Sau đó, chúng ta di chuyển đến


đỉnh 3 và 5:
Cuối cùng, chúng ta duyệt 6:

Bây giờ chúng ta tính toán khoảng cách từ đỉnh bắt đầu đến tất cả các đỉnh của đồ thị. Khoảng cách như sau:
Đỉnh Khoảng cách
1 0
2 1
3 2
4 1
5 2
6 3
Giống như tìm kiếm theo chiều sâu, độ phức tạp của tìm kiến theo chiều rộng là O(n + m), khi n là số lượng đỉnh
và m là số lượng cạnh.
c) Thực thi mã

Tìm kiếm theo chiều rộng là khó thực thi mã hơn tìm kiếm theo chiều sâu, vì
thuật toán viếng thăm các đỉnh trong nhiều đường khác nhau của đồ thị. Một
thực thi điển hình là dựa trên một hàng đợi (queue) chứa các đỉnh. Tại mỗi
bước, đỉnh tiếp theo trong hàng đợi sẽ được xử lý.

Mã sau giả thuyết rằng đồ thị được lưu trữ dạng danh sách kề và duy trì một
cấu trúc dữ liệu như sau:

queue<int> q;
bool visited[N];
int distance[N];
Hàng đợi q chứa các đỉnh để xử lý theo thứ tự tăng dần khoảng cách của chúng. Các
đỉnh mới luôn được thêm vào cuối hàng đợi, và một đỉnh tại đầu hàng đợi là đỉnh tiếp
theo được xử lý. Mảng visited chỉ ra các đỉnh mà việc tìm kiếm đã viếng thăm, và mảng
distance sẽ chứa khoảng cách từ đỉnh bắt đầu đến tất cả các đỉnh khác của đồ thị.

Việc tìm kiếm có thể được thực thi như sau, bắt đầu từ đỉnh x:
visited[x] = true;
distance[x] = 0;
q.push(x);
while(!q.empty()) {
int s = q.front(); q.pop()
// process node s
for(auto u : adj[s]) {
if(visited[u]) continue;
visited[u] = true;
distance[u] = distance[s] + 1;
q.push(u);
}
}
THANK'S FOR
WATCHING

You might also like