Bạn đọc tự tìm hiểu phương pháp thử nghiệm thuật toán Dijkstra trong các tài liệu liên quan.
d) Cài đặt thuật toán
#include <iostream> #include <fstream> #define MAX 100 using namespace std;
//hàm tìm đỉnh có nhãn nhỏ nhất
int minDistance(int dist[], bool sptSet[], int n){ // thiết lập nhãn nhỏ nhất ban đầu
int min = INT_MAX, min_index; for (int v = 1; v <= n; v++){
if (sptSet[v] == false && dist[v] <= min){ min = dist[v]; min_index = v;
}
}
return min_index;//đỉnh có nhãn nhỏ nhất
}
// hàm in ra độ dài đường đi ngắn nhất
int printSolution(int dist[], int n){ printf("Đường đi ngắn: \n"); for (int i = 1; i <= n; i++)
printf("%d \t\t %d\n", i, dist[i]); }
// thuật toán Dijkstra sử dụng ma trận kề
void dijkstra(int graph[MAX][MAX], int src, int n) {
int dist[MAX]; // dist[i] sẽ là độ dài đường đi ngắn nhất từ src đến i bool sptSet[MAX]; //lưu trữ đường đi ngắn nhất từ src đến i
//Bước 1 (khởi tạo): thiết lập tất cả độ dài là INF. for (int i = 1; i <= n; i++){
dist[i] = INT_MAX; sptSet[i] = false; }
dist[src] = 0; //nhãn đỉnh xuất phát lấy là 0
//Bước 2(lặp): tìm đường đi ngắn nhất từ src đến tất cả các đỉnh
NGUYỄN DUY PHƯƠNG 216 int u = minDistance(dist, sptSet,n);//lấy u là đỉnh có nhãn nhỏ nhất int u = minDistance(dist, sptSet,n);//lấy u là đỉnh có nhãn nhỏ nhất
sptSet[u] = true; //đánh dấu đỉnh u đã là đường đi ngắn nhất
// cập nhật nhãn các đỉnh còn lại
for (int v = 1; v <= n; v++) {
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u]+graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v]; }
}
printSolution(dist, n); // in ra đường đi ngắn nhất
}
int main() {
int n, m, dau, cuoi, trongso; //khai báo số đỉnh và số cạnh: n, m
int graph[MAX][MAX]; //ma trận kề biểu diễn đồ thị
ifstream fp("dothiw.in"); //file biểu diễn đồ thị dưới dạng danh sách cạnh
fp>>n>>m; //đọc số cạnh và số đỉnh của đồ thị
for(int i=1; i<=m; i++){ //đọc m cạnh: (dau, cuoi, trongso) fp>>dau>>cuoi>>trongso;
graph[dau][cuoi]= trongso;
graph[cuoi][dau]= trongso;//bỏ đi nếu là đồ thị có hướng
}
fp.close();
dijkstra(graph, 1, 9); }
6.6.2. Thuật toán Bellman-Ford
Thuật toán Bellman-Ford dùng để tìm đường đi ngắn nhất trên đồ thị không có chu trình âm. Do vậy, trong khi thực hiện thuật toán Bellman-Ford ta cần kiểm tra đồ thị có chu trình âm hay không. Trong trường hợp đồ thị có chu trình âm, bài toán sẽ không có lời giải. Thuật toán được thực hiện theo k = n - 2 vòng lặp trên tập đỉnh hoặc tập cạnh tùy thuộc vào dạng biểu diễn của đồ thị. Nếu đồ thị được biểu diễn dưới dạng ma trận kề, độ phức tạp thuật toán là O(V3), với V là số đỉnh của đồ thị. Trong trường hợp đồ thị được biểu diễn dưới dạng danh sách cạnh, độ phức tạp thuật toán là O(V.E), với V là số đỉnh của đồ thị, E là số cạnh của đồ thị. Thuật toán được mô tả chi tiết trong Hình 5.18 cho đồ thị biểu diễn dưới dạng ma trận kề.
NGUYỄN DUY PHƯƠNG 217
a) Biểu diễn thuật toán
Hình 5.18. Thuật toán Bellman-Ford
b) Độ phức tạp thuật toán
Độ phức tạp thuật toán là O(VE), trong đó V, E là số đỉnh và số cạnh của đồ thị. Bạn đọc tự tìm hiểu và chứng minh độ phức tạp thuật toán Bellman-Ford trong các tài liệu liên quan.
c) Thử nghiệm thuật toán
Bạn đọc tự tìm hiểu phương pháp thử nghiệm thuật toán Bellman-Ford trong các tài liệu liên quan.
d) Cài đặt thuật toán
#include <iostream.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #define MAX 100 #define MAXC 10000
Thuật toán Bellman-Ford (s): //s V là đỉnh bất kỳ của đồ thị
Begin:
Bước 1 (Khởi tạo):
for vV do { //Sử dụng s gán nhãn cho các đỉnh vV D[v] = A[s][v]; Truoc[v] = s; } Bước 2 (Lặp) : D[s] = 0; K=1; while (K<=N-2 ) { //N-2 vòng lặp
for vV\{s} do { //Lấy mỗi đỉnh vV\s
for uV do { //Gán nhãn cho v if (D[v] > D[u] + A[u][v] ) { D[v]= D[u] + A[u][v]; Truoc[v] = u; endif; endfor; endfor; endwlie;
Bước 3 (Trả lại kết quả):
Return( D[v], Truoc[v]: vU);
NGUYỄN DUY PHƯƠNG 218 int C[MAX][MAX]; //Ma tran trong so bieu dien do thi int C[MAX][MAX]; //Ma tran trong so bieu dien do thi
int D[MAX]; //Do dai duong di int Trace[MAX]; //Luu lai vet duong di
int n, m, S, F; // n:So dinh; S: Dinh bat dau; F: Dinh ket thuc FILE *fp;
void Read_Data(void){
int i, u, v;fp = fopen("dothi.in","r");
fscanf(fp,"%d%d%d%d",&n,&m,&S,&F); for(u=1; u<=n; u++)
for(v=1; v<=n; v++)
if (u==v) C[u][v]=0;
else C[u][v]=MAXC; for(i=1; i<=m; i++)
fscanf(fp,"%d%d%d",&u,&v,&C[u][v]); fclose(fp);
}
void Init(void){ int i;
for( i=1; i<=n; i++){ D[i] = C[S][i]; Trace[i]=S; }
}
void Result(void){
if (D[F]==MAXC) printf("\n Khong co duong di"); else {
printf("\n Do dai %d den %d: %d", S, F, D[F]); while (F!=S ){ printf("%d <--",F); F = Trace[F]; } } } void Ford_Bellman(void){ int k, u, v;D[S]=0; for( k=1; k<=n-2; k++){ for(v=1; v<=n; v++){
for( u=1; u<=n; u++){
if (D[v]>D[u]+C[u][v]){ D[v] = D[u]+C[u][v]; Trace[u]=v;
} }
NGUYỄN DUY PHƯƠNG 219 } } } } int main() { Read_Data();Init(); Ford_Bellman(); Result(); system("PAUSE"); return 0; }