6.5. Bài toán xây dựng cây khung của đồ thị
6.5.1. Xây dựng cây khung của đồ thị bằng thuật toán DFS
Khi ta thực hiện thủ tục tìm kiếm theo chiều sâu bắt đầu tại đỉnh uV, ta nhận được tập đỉnh vV có cùng thành phần liên thông với u. Nếu DFS(u) = V thì ta kết luận đồ thị liên thông và phép duyệt DFS(u) đi qua đúng n-1 cạnh. Nếu Nếu DFS(u) V thì ta kết luận đồ thị không liên thông. Chính vì vậy, ta có thể sử dụng phép duyệt DFS(u) để xây dựng cây khung của đồ thị. Trong mỗi bước của thuật toán DFS, xuất phát tại đỉnh u ta sẽ thăm được đỉnh v và ta kết nạp cạnh (u,v) vào tập cạnh của cây khung. Các bước tiếp theo được tiến hành tại đỉnh v cho đến khi kết thúc thuật toán DFS. Thuật toán được xây dựng dựa vào ngăn xếp được mô tả chi tiết trong Hình 5.14.
a) Biểu diễn thuật toán
Hình 5.14. Xây dựng cây khung của đồ thị bằng thuật toán DFS.
Thuật toán Tree-DFS(u):
Begin
Bước 1 (Khởi tạo):
T = ; //tập cạnh cây khung ban đầu.
stack = ; //thiết lập stack rỗng;
Push(stack, u); //đưa u vào stack;
chuaxet[u] = False;//bật trạng thái đã xét của đỉnh u Bước 2 (Lặp):
while (stack ) do { //lặp cho đến khi stack rỗng s = Pop(stack); //lấy s ra khỏi stack
for each tKe(s) do { //lặp trên danh sách Ke(s) if (chuaxet[t] ) then { //nếu đỉnh t chuaxet
Push(stack, s);// đưa s vào stack trước Push(stack, s);// đưa t vào stack sau T = T(s,t); //kết nạp (s,t) vào cây khung chuaxet[t] = False; //ghi nhận t đã xét break ;//chỉ lấy đỉnh đầu tiên
endif ; endfor ; endwwhile ;
Bước 3 (Trả lại kết quả) :
if (| T | < n-1 ) <Đồ thị không liên thông> ; else <Ghi nhận tập cạnh T của cây khung> ; end.
NGUYỄN DUY PHƯƠNG 202
b) Độ phức tạp thuật toán
Độ phức tạp thuật toán Tree-DFS(u) đúng bằng độ phức tạp thuật toán DFS(u).
c) Kiểm nghiệm thuật toán
Bạn đọc tự tìm hiểu và kiểm nghiệm thuật toán trong các tài liệu tham khảo liên quan.
d) Cài đặt thuật toán
#include<iostream>
#include <list>
#include <fstream>
#include <iomanip>
#include <stack>
using namespace std;
struct canh{ //biểu diễn một cạnh của đồ thị int dau; //đỉnh đầu của cạnh
int cuoi; //đỉnh cuối của cạnh };
class Graph{ //xây dựng lớp đồ thị private:
int V; // số đỉnh của đồ thị
list<int> *adj; // con trỏ đến mảng các danh sách kề bool *chuaxet; //mảng chưa xét
canh *T;//tập cạnh của cây khung int sc; //số cạnh của cây khung public:
Graph(int V); // constructor của lớp
void addEdge(int v, int w); // thêm một cạnh vào đồ thị void Tree_BFS(int u);//thuật toán Tree-BFS
void Tree_DFS(int u);//thuật toán Tree-DFS };
Graph::Graph(int V){ //constructor của lớp this->V = V;//thiết lập tập đỉnh
adj = new list<int>[V];//thiết lập V danh sách kề
T = new canh[V]; sc =1; //thiết lập số cạnh cây khung chuaxet = new bool[V];//thiết lập giá trị mảng chưa xét for(int u=0; u<V; u++) chuaxet[u]=true;
}
void Graph::addEdge(int v, int w){ //thêm một cạnh vào danh sách kề adj[v].push_back(w); // thêm w vào list(v)
NGUYỄN DUY PHƯƠNG 203
adj[w].push_back(v); // thêm v vào list(w) }
void Graph::Tree_DFS(int u){
//Bước 1 (Khởi tạo):
stack <int> Stack; //tạo lập stack rỗng Stack.push(u);//đưa u vào ngăn xếp chuaxet[u] = false; //xác nhận u đã xét list<int>::iterator t; //t là iterator của list while(!Stack.empty()){//lặp đến khi stack rỗng
int s = Stack.top(); //lấy s là đỉnh đầu ngăn xếp Stack.pop();//loại s ra khỏi ngăn xếp
for (t = adj[s].begin(); t != adj[s].end(); ++t){//duyệt trên list(s) if(chuaxet[*t]){//nếu đúng t chưa xét
Stack.push(s);//đưa s vào stack trước
Stack.push(*t); //đưa t vào stack sau
chuaxet[*t]=false; //ghi nhận t đã xét
T[sc].dau = s;T[sc].cuoi = *t;//thêm (s,t) vào cây
sc++; //tăng số cạnh lên 1
break;//chỉ lấy đỉnh đầu tiên
} }
}
if(sc<V-1){//nếu |T|<n-1
cout<<"\n Đồ thị không liên thông";
} else {
cout<<"\n Tập cạnh cây khung:"<<endl;
for(int i=1; i<sc; i++){
cout<<T[i].dau<<setw(3)<<T[i].cuoi<<endl;
} }
}
int main(void){
ifstream fp("Graph.in"); //mở file để đọc int n, m, dau, cuoi;
fp>>n>>m;//đọc số đỉnh và số cạnh của đồ thị Graph gh(n+1);//thiết lập đồ thị gồm n đỉnh
NGUYỄN DUY PHƯƠNG 204
for(int i=1; i<=m; i++){//chuyển đồ thị sang danh sách kề fp>>dau>>cuoi;
gh.addEdge(dau, cuoi);
}
fp.close();
gh.printGraph();
gh.Tree_BFS(1);
}