Tìm kiếm theo chiều sâu DFS-Depth First Search Trong tìm kiếm theo chiều sâu, tại trạng thái đỉnh hiện hành, ta chọn một trạng thái kế tiếp trong tập các trạng thái có thể biến đổi thành
Trang 1CHƯƠNG 1: MỞ ĐẦU
1 Dẫn nhập
Tìm kiếm là hoạt động rất phổ biến trong đời sống Trong khoa học máy tính, chiến lược tìm kiếm còn có ý nghĩa quyết định đến thành bại của nhiều tác vụ khác Với sự phát triển nhanh của các ngành như Hệ thống thông tin địa lý, mạng xã hội … đã tạo nên những cơ sở dữ liệu rất lớn và phát sinh nhiều chiến lược lưu trữ mới Tất cả đã làm cho không gian tìm kiếm ngày càng rộng lớn hơn Vậy nên việc nghiên cứu để đưa ra những phương pháp tìm kiếm thích hợp là một thách thức mà chúng ta phải đối mặt
Qua môn học Cơ sở dữ liệu nâng cao do PGS TS Đỗ Phúc phụ trách, tôi đã tiếp thu được nhiều kiến thức bổ ích Một trong số đó là kiến thức về tìm kiếm trong cơ sở dữ liệu đồ thị (CSDLĐT) CSDLĐT có không gian rất rộng lớn nên sẽ phát sinh rất nhiều phương án trong các bước lặp Việc chọn hay loại một phương án có ảnh hưởng rất nhiều đến kết quả cũng như hiệu quả của giải thuật Càng nghiên cứu tôi càng thấy thích thú nên chọn đề tài “Các chiến lược tìm kiếm đường đi trong cơ sở
dữ liệu đồ thị cở lớn” để làm tiểu luận cho môn học này
Trước khi đi vào các phần sau của bài thu hoạch, cho phép tôi được gửi lời cảm ơn sâu sắc tới Thầy Đỗ Phúc và các Thầy Cô ở trường Đại học Công nghệ Thông tin – Đại học Quốc gia Tp HCM Các Thầy Cô đã tạo điều kiên rất tốt để chúng tôi có được chương trình học phù hợp và hiệu quả Chúc các Thầy Cô được nhiều sức khỏe và thành công
2 Đặt vấn đề
Chiến lược tìm kiếm theo chiều sâu DFS (Deep First Search) và tìm kiến theo chiều rộng BrFS (Breath First Search) trong trường hợp xấu nhất đều trở thành vét cạn toàn bộ Do đó sẽ tốn nhiều thời gian hay bộ nhớ của máy tính Hơn nữa, nếu không gian tìm kiếm lớn thì vét cạn là một trở ngạy không nhỏ nếu không muốn nói là không thể áp dụng được
Để tránh vét cạn toàn bộ, ngày nay đã có nhiều chiến lược tìm kiếm Heuristic khá hiệu quả Tuy nhiên để có một hàm Heuristic thực sự hiệu
Trang 2quả trong một số bài toán thì ta phải trả một giá không hề rẻ, thậm chí có một số bài toán chưa tìm ra hàm heuristic thích hợp Cụ thể trong tìm kiếm đường đi ngắn nhất từ một thành phố X đến một thành phố Y áp dụng thuật giải A*1, hàm heuristic h’ thường là khoảng cách đường chim bay giữa chúng Vậy ta phải bỏ chi phí tìm và cài đặt khoảng cách chim bay này trong cơ sỏ dữ liệu để phục vụ tìm kiếm Trong mạng xã hội, ta không thể tìm ra khoảng cách đường chim bay giữa hai nút
3 Giải quyết vấn đề
Để giải quyết vấn đề trên, ta có thể áp dụng chiến lược vét cạn thông minh Nói cách khác là dựa vào thông tin về độ dài đường đi ở thời điểm hiện tại của một nút K nào đó, ta so sánh với độ dài đường đi tới chính nó nhưng xuất hiện ở một hướng đi khác Từ đó chọn được hướng
đi tốt hơn và loại bỏ những phương án không tốt hoặc không còn khả năng phát sinh hướng đi mới
Tuy nhiên, như đã nêu, trong trường hợp xấu nhất và không gian tìm kiếm là ma trận cỡ 106 x 106 trở lên thì vét cạn sẽ tốn rất nhiều thời gian và bộ nhớ Ta có thể áp dụng phương thức chọn lọc theo hướng tiến hóa của thuật giải di truyền để loại bỏ những phương án có độ thích nghi thấp Từ đó có thể giới hạn số lượng phương án phải duyệt của chiến lược tìm kiếm
4 Nội dung nghiên cứu
1 Tổng hợp một số chiến lược tìm kiếm đường đi trong đồ thị
2 Chiến lược vét cạn thông minh
3 Lý thuyết về thuật giải di truyền
4 Áp dụng phương thức chọn lọc tiến hóa vào vét cạn thông minh
5 Phương pháp nghiên cứu
1 Phương pháp biện chứng và các quy tắc của nó
2 Sưu khảo tài liệu, phân tích, so sánh, tổng hợp
3 Thực nghiệm
CHƯƠNG 2: NỘI DUNG
1 Thuật toán A được mô tả lần đầu tiên vào năm 1968 bởi Peter Hart, Nils Nilsson và Bertram Rephael
Trang 3I TỔNG HỢP MỘT SỐ CHIẾN LƯỢC TÌM KIẾM ĐƯỜNG ĐI
TRONG ĐỒ THỊ
1 Tìm kiếm theo chiều sâu (DFS-Depth First Search)
Trong tìm kiếm theo chiều sâu, tại trạng thái (đỉnh) hiện hành, ta chọn một trạng thái kế tiếp (trong tập các trạng thái có thể biến đổi thành từ trạng thái hiện tại) làm trạng thái hiện hành cho đến lúc trạng thái hiện hành là trạng thái đích Trong trường hợp tại trạng thái hiện hành, ta không thể biến đổi thành trạng thái kế tiếp thì ta sẽ quay lui (backtracking) lại trạng thái trước trạng thái hiện hành (trạng thái biến đổi thành trạng thái hiện hành) để chọn đường khác Nếu ở trạng thái trước này mà cũng không thể biến đổi được nữa thì ta quay lui lại trạng thái trước nữa và cứ thế Nếu đã quay lui đến trạng thái khởi đầu mà vẫn thất bại thì kết luận là không có lời giải
2 Tìm kiếm theo chiều rộng (BrFS-Breath First Search)
Ngược lại với tìm kiếm theo kiểu chiều sâu, tìm kiếm chiều rộng mang hình ảnh của vết dầu loang Từ trạng thái ban đầu, ta xây dựng tập hợp S bao gồm các trạng thái kế tiếp (mà từ trạng thái ban đầu có thể biến đổi
thành) Sau đó, ứng với mỗi trạng thái Tk trong tập S, ta xây dựng tập Sk
bao gồm các trạng thái kế tiếp của Tk rồi lần lượt bổ sung các Sk vào S Quá trình này cứ lặp lại cho đến lúc S có chứa trạng thái kết thúc hoặc S không thay đổi sau khi đã bổ sung tất cả Sk
3 Tìm kiếm theo lựa chọn tốt nhất (BFS-Best First Search)
Ưu điểm của tìm kiếm theo chiều sâu là không phải quan tâm đến sự
mở rộng của tất cả các nhánh Ưu điểm của tìm kiếm chiều rộng là không
bị sa vào các đường dẫn bế tắc (các nhánh cụt) Tìm kiếm ưu tiên tối ưu sẽ kết hợp 2 phương pháp trên cho phép ta đi theo một con đường duy nhất tại một thời điểm, nhưng đồng thời vẫn "quan sát" được những hướng khác Nếu con đường đang đi "có vẻ" không triển vọng bằng những con đường ta đang "quan sát" ta sẽ chuyển sang đi theo một trong số các con đường này Để tiện lợi ta sẽ dùng chữ viết tắt BFS thay cho tên gọi tìm kiếm ưu tiên tối ưu Một cách cụ thể, tại mỗi bước của tìm kiếm BFS, ta
Trang 4chọn đi theo trạng thái có khả năng cao nhất trong số các trạng thái đã
được xét cho đến thời điểm đó Như vậy, với tiếp cận này, ta sẽ ưu tiên đi
vào những nhánh tìm kiếm có khả năng nhất, nhưng ta sẽ không bị lẩn quẩn trong các nhánh này vì nếu càng đi sâu vào một hướng mà ta phát hiện ra rằng hướng này càng đi thì càng tệ, đến mức nó xấu hơn cả những hướng mà ta chưa đi, thì ta sẽ không đi tiếp hướng hiện tại nữa mà chọn đi theo một hướng tốt nhất trong số những hướng chưa đi
4 Tìm kiếm Heuristic với A*
Tương tự như BFS nhưng A* lựa chọn trạng thái có khả năng tốt nhất
để đi dựa vào một hàm heuristic f(x)=g(x)+h(x) Trong đó g(x) là tổng độ dài từ đỉnh xuất phát đến đỉnh hiện tại và h(x) là hàm ước lượng khoảng cách còn lại giữa đỉnh hiện tại và đỉnh đích (có thể là khoảng cách đường chim bay) Đồng thời vẫn quan sát các trạng thái khác, khi phát hiện trạng thái mà hướng đi hiện tại xấu hơn các trạng thái đang quan sát thì sẽ chuyển hướng đi theo các trạng thái tốt hơn này
II PHƯƠNG PHÁP VÉT CẠN THÔNG MINH
Nhữ đã nêu, các chiến lược tìm kiếm nói trên có những nhược điểm cố
hủ của chúng Do đó, khi áp dụng vào thực tế, người ta ít khi áp dụng nguyên bản một phương án nào mà phải hiệu đính cho phù hợp với yêu cầu thực tế hoặc kết hợp nhiều phương án với nhau Trong phần này, chúng ta sử dụng một phương pháp vét cạn nhưng có điều kiện Phương pháp này sử dụng chiến lược BrFS kết hợp với BFS
1 Mô tả bài toán
Cho một mạng xã hội có n (n<=105) nút, mỗi nút có thể liên kết tới n-1 nút khác và ta gọi liên kết này là liên kết “là bạn của”, mỗi liên kết như vậy có một nhãn là số nguyên thể hiện tần suất trao đổi thông tin cho nhau giữa hai nút Hãy tìm ra một dãy liên kết không có hai nút giống nhau và ít trao đổi thông tin nhất giữa hai nút A và B trong mạng nói trên Giả định rằng ở hai nút bất kỳ ta luôn có tần suất phản hồi bằng với tần suất nhận được thông tin
Trang 5Bài toán trên có thể mô tả lại như sau: Cho đồ thị vô hướng G(V,E) có trọng số Trong đó V là tập đỉnh và E là tập cạnh của G Hãy tìm đường đi ngắn nhất giữa hai đỉnh bất kỳ trong G
2 Mô tả giải thuật
Ý tưởng của giải thuật này như sau: tại mỗi bước lặp, ta đưa vào tập đỉnh (tạm gọi là tập phương án-mỗi đỉnh như vậy là một phương án mới tạm gọi là Tk) nối tập đỉnh đang xét với điều kiện tổng chiều dài từ đỉnh xuất phát đến các đỉnh Tk phải nhỏ hơn chiều dài nhỏ nhất của Tk ở bước trước Giải thuật kết thúc khi trong tập phương án tồn tại đỉnh cần tìm và không thể phát sinh thêm phương án mới Giải thuật cũng kết thúc khi tập phương án là rỗng, khi đó sẽ không tồn tại đường đi giữa hai đỉnh đã cho Thuật giải được mô tả bằng mã giả như sau:
Flag=StartNode;
For (i=1;i<=n;i++){CurrentMin[i]= ∞};
CountAdded=0;CountEndNode=0;CountSolution=0; While (Flag !=NULL)
For each T {
If (Tk.Length+Flag.Length<=CurrentMin[Tk]) {
Flag=Flag+Tk;
CurrentMin[Tk]= Tk.Length+Flag.Length; CountAdded++;
If (Tk==EndNode) CountEndNode++;
}//end if }//end for
If(CountAdded==0) Delete Flag.Node
CountSolution++;
Flag=Flag.NextNode;
}/ /end while
Với đồ thị trong ví dụ sau đây, tại mỗi bước lặp ta thu được tập phương án là tập các nút bên trái nhất
3 Cấu trúc dữ liệu
Trang 6Mỗi nút được biểu diễn bằng môt record như sau:
struct node{
int Dinh;
int DoDai;
struct node* NextCol;
struct node* NextRow;
};
Trong đó:
- Dinh: lưu đỉnh đang xét và các đỉnh đã đi qua
- DoDai: tổng độ dài từ đỉnh xuất phát đến đỉnh đang xét
- NextCol: pointer liên kết các nút mà nút hiện tại đã đi qua -NextRow: pointer liên kết các nút trong tập phương án
Độ dài nhỏ nhất từ đỉnh xuất phát đến Tk được lưu trong một mảng một chiều:
int CurrentMin[n]
4 Cài đặt giải thuật
a Khởi tạo không gian tìm kiếm
Không gian tìm kiếm là ma trận n x n kiểu số nguyên, ta khởi tạo
số nguyên bằng hàm rand()%x (với x đủ lớn để không tồn tại nhiều phương án có cùng độ dài) Đối với ma trận cở nhỏ có thể cài đặt các giá trị giao của hàng và cột ma trận ngay trong thủ tục khởi tạo Chúng
ta có thể đọc từ tập tin lưu trữ trên đĩa Thủ tục InitSearchSpace() được cài đặt như sau
void InitSearchSpace(){
int i,j,k;
for (i=1;i<=n-1;i++)
for (j=1;j<=n-1;j++)
if(j!=i){
k=rand()%1000;
KG[i][j]=k;KG[j][i]=k;
} }
b Đưa đồ thị vào danh sách kề
Để giảm số bước lặp không cần thiết khi thực hiện dòng For tìm ra đỉnh nối đỉnh đang xét trong ma trận, ta dùng danh sách kề để lưu trữ
đồ thị Thủ tục DuaVaoDSKG() được cài đặt như sau
Trang 7void DuaVaoDSKG(){
int i,j,dem;
for(i=1;i<n;i++){
dem=0;
for (j=1;j<n;j++)
if (KG[i][j]!=0){
dem++;
DSKG[i].Dinh[dem]=j;
DSKG[i].DoDai[dem]=KG[i][j];
} DSKG[i].Dinh[0]=dem;
}
}
c Khởi tạo đỉnh bắt đầu:
void InitSolution(int DinhBD){
struct node* NewNode = malloc(sizeof(struct node));
NewNode->Dinh=DinhBD;
NewNode->DoDai=0;
NewNode->NextCol=NULL;
NewNode->NextRow=NULL;
First=NewNode;
Last=NewNode;
}
d Xây dượng phương án mới
Trong khi xây dựng tập phương án mới ta cần chú ý các điểm sau: + Chỉ đưa vào tập phương án những nút nào có tổng chiều dài từ đỉnh xuất phát đến Tk là nhỏ hơn chiều dài nhỏ nhất của chính Tk ở các bước trước Như vậy bước đầu tiên ta phải khởi tạo giá trị nhỏ nhất trong CurrentMin[] là số đủ lớn (tương nhự như nhãn ∞ trong thuật toán Dijkstra)
+ Nếu đã thêm được Tk vào tập phương án thì phải cập nhật lại độ dài nhỏ nhất đến Tk trong CurrentMin[]
+ Đếm các phương án là đỉnh kết thúc, số lượng các phương án mới phát sinh và tổng số lượng phương án hiện có Việc này để giúp ta thực hiện thao tác dừng giải thuật như đã nêu
+ Cần xử lý tốt các trường hợp không thể phát sinh thêm phương
án tại đỉnh đang xét Để giảm số lượng phương án và mau chóng kết thúc giải thuật
Trang 8Thủ tục InsertSolution() được cài đặt như sau.
void InsertSolution(int DinhKT){
struct node* Row=First;
Last=First;
int i,dem,k;
Count_Solution_1=0;
Count_Solution_2=0;
SoLuongCaThe=0;
while (Row != NULL){
dem=0;
if(Row->Dinh!=DinhKT){
for(i=1;i<=DSKG[Row->Dinh].Dinh[0];i++){
k=Row->DoDai+DSKG[Row->Dinh].DoDai[i];
if(k<=CurrentMin[DSKG[Row->Dinh].Dinh[i]]){
dem++;
struct node* w = malloc(sizeof(struct node));
w->Dinh=DSKG[Row->Dinh].Dinh[i];
w->DoDai=k;
w->NextCol=Row;
w->NextRow=Row->NextRow;
if (w->Dinh==DinhKT){Count_Solution_1++;}
CurrentMin[DSKG[Row->Dinh].Dinh[i]]=k;
Count_Solution_2++;
if((Row==First)&&(dem=1))First=w;
else Last->NextRow=w;
Last=w;
} // end if CurrentMin }// end for
if(dem==0){
if(Row==First){First=First->NextRow;}
else if(Row->NextRow==NULL){Last->NextRow=NULL;} else {Last->NextRow=Row->NextRow;}
}//end if dem =0 }else Count_Solution_1++;// end if bo qua dinh dich
if(dem==0) Last=Row;
SoLuongCaThe++;
Row=Row->NextRow;
Trang 9}//end while
}
e Chọn lọc phương án
Dễ thấy rằng sau mỗi bước lặp, vẫn còn tồn tại những phương án
có độ dài lớn hơn CurrenMin[] do có nhiều đường đi đến đỉnh Tk mà việc tìm ra phương án có độ dài nhỏ nhất nằm ở cuối tập phương án Vậy nên ta phải xây dựng một thủ tục loại bỏ những phương án này Thủ tục ChonLoc() được cài đặt như sau
void ChonLoc(){
struct node* Row=First;
struct node* Temp;
struct node* SauRow;
int f=0;
SauRow=Row;
while (Row!=NULL){
f=0;
if(Row->DoDai>CurrentMin[Row->Dinh]){
SoLuongCaThe ;
Temp=Row;
if (Row!=SauRow){
SauRow->NextRow=Row->NextRow;
f=1;
} else{
First=Row->NextRow;
SauRow=First;
Row=First;
f=2;
} }// end if lon hon do dai
if (f==0) SauRow=Row;
if (f!=2) Row=Row->NextRow;
if (f>0){// co xay ra truong hop xoa Temp->NextCol=NULL;
Temp->NextRow=NULL;
free(Temp);
} }
}
f abc
5 Đánh giá …
Trang 10III VÉT CẠN THÔNG MINH KẾT HỢP CHỌN LỌC TIẾN HÓA
Ta thấy rằng, bài toán tìm đường đi ngắn nhất trong đồ thị chính là dạng bài toán tối ưu hàm số nhiều biến, mà tổng các biến đó là độ dài nhỏ nhất từ đỉnh xuất phát đến đỉnh Tk Bài toán được phát biểu như sau:
Cho hàm số f(v)= ∑n
= i i
v
1
; Xác định tập V{ v1, v2, … vn } sao cho f(v) ≤ k với k[i] là giá trị trong CurrentMin[i] Với dạng bài toán này, việc áp dụng thuật giải di truyền giải quyết là rất thích hợp
Tuy nhiên, ở bài thu hoạch này, chúng ta chỉ áp dụng một số cơ sở lý thuyết của thuật giải di truyền trong việc chọn lọc các phương án Ta xem mỗi nút trong tập phương án là một cá thể (nhiễm sắc thể - NST) và hàm mục tiêu là độ dài của nút đó ở thời điểm đang xét Công việc của chúng
ta là xây dựng cách tính độ thích nghi và các phương pháp chọn lọc như thế nào để có thể loại bỏ những phương án không tốt
1 Độ thích nghi
Độ thích nghi là xác suất để NST được chọn lọc, làm cơ sở phát sinh thế hệ tiếp theo Vậy tại sao ta không chọn hàm mục tiêu để xác định xác suất chọn lọc mà lại phải dựa vào độ thích nghi? Ta biết rằng trong một quần thể thường có xu hướng các cá thể phát triển không đồng đều, có một vài cá thể phát triển quá tốt Nếu chọn cá thể phát triển quá tốt mà bỏ
đi những cá thể phát triển trung bình sẽ làm giảm mạnh số lượng cá thể ở thế hệ tiếp theo Hơn nữa cá thể phát triển tốt này chưa hẳn sẽ phát sinh những thế hệ lời giải tối ưu Người ta ví quá trình chọn lọc lệch như thế là
di truyền cục bộ Vậy để tránh hiện tượng di truyền cục bộ, người ta đưa
ra phương pháp chọn lọc dựa trên độ thích nghi của cá thể
a Độ thích nghi tiêu chuẩn
Độ thích nghi tiêu chuẩn là độ thích nghi được xác định dựa trên độ tốt của lời giải, nghĩa là dựa vào hàm mục tiêu