MỤC LỤC LỜI NÓI ĐẦU 3 Phân tích bài toán 4 Phát biểu bài toán 4 Mô tả bài toán hệ thống dây điện 4 Thuật toán Prim 4 Giới thiệu thuật toán 4 3 Mô tả thuật toán Prim 6 Giải thuật bài toán hệ thống dây.
Trang 1MỤC LỤC
LỜI NÓI ĐẦU 3
I Phân tích bài toán 4
1 Phát biểu bài toán 4
2 Mô tả bài toán hệ thống dây điện 4
II Thuật toán Prim 4
1 Giới thiệu thuật toán 4
3 Mô tả thuật toán Prim 6
III Giải thuật bài toán hệ thống dây điện áp dụng thuật toán Prim 9
1 Cài đặt thuật toán 9
2 Chương trình giải quyết bài toán hệ thống dây điện 9
TỔNG KẾT 16
Trang 2LỜI NÓI ĐẦU
Lý thuyết đồ thị là một trong những công cụ quan trọng có nhiều ứng dụng các lĩnh vực khác nhau trong cuộc sống Lý thuyết đồ thị sử dụng để nghiên cứu, làm đơn giản hóa và giải các bài toán trong khi việc giải bài toán đó bằng công cụ khác của toán học rất khó khăn
Cùng với sự phát triển của xã hội, việc di chuyển cả về con người, hàng hóa và thông tin,… càng ngày càng gia tăng Cùng cới sự gia tăng đó thì yêu cầu cực tiểu về chi phí, khoảng cách, thời gian, cũng trở lên quan trọng hơn Theo lý thuyết đồ thị đó
là bài toán tìm đường đi ngắn nhất giữa các đỉnh của 1 đồ thị Chẳng hạn bài toán tìm đường đi ngắn nhất giữa các thành phố, Bài toán tìm tuyến xe buýt từ địa điểm này đến địa điểm kia sao cho tiết kiệm chi phí nhất,… Bài toán tìm đường đi ngắn nhất càng trở nên cấp thiết và quan trọng đối với cả hiện tại và tương lai
Do sự quan trọng và cấp thiết của bài toán tìm đường đi ngắn nhất nên đã có nhiều nhà toán học đã đưa ra nhiều thuật toán để giải và được vận dụng vào để giải quyết nhiều bài toán thực tế Trong số các thuật toán được đưa ra thì có thuật toán Prim -tìm cây khung nhỏ nhất
Trang 3I Phân tích bài toán
1 Phát biểu bài toán
Có n phòng làm việc trong một công ty và giữa các phòng làm việc xác định một thông số là khoảng cách Một đường đi xuất phát từ một đỉnh bất kỳ qua các phòng làm việc còn lại sao cho các phòng đều có điện Tìm đường đi ngắn nhất của dây điện Giải bài toán bằng phương pháp tìm đường đi ngắn nhất – thuật toán Prim
2 Mô tả bài toán hệ thống dây điện
Bài toán hệ thống dây điện biểu diễn thành một đồ thị, trong đó các phòng làm việc được biểu diễn dưới dạng các đỉnh, các đường daay điện nối giữa các phòng biểu diễn dươi dạng giá trị các cạnh nối các đỉnh Tuy nhiên, đồ thị sau khi được xây dựng dựa và các đỉnh và đường nối dây điện là đồ thị hoàn chỉnh và đủ, giữa các phòng làm việc không có đường đi trực tiếp được nối với nhau mà phải thông qua một hoặc nhiều căn phòng trung gian khác ta gán trọng số của các cạnh đó lớn nhất có thể Khi đó, bài toán hệ thống dây điện trở thành bài toán tìm đường
đi ngắn nhất
Nếu như khoảng cách giữa hai phòng bất kỳ như nhau cho cả hai hướng
thì dùng đồ thì vô hướng, ngược lại ta sử dụng đồ thị có hướng
II Thuật toán Prim
1 Giới thiệu thuật toán
Trong khoa học máy tính, thuật toán Prim là một thuật toán tham lam để tìm cây bao trùm nhỏ nhất của đồ thị vô hướng có trọng số liên liên thông Nghĩa là nó
Trang 4tìm một tập hợp các cạnh của đồ thị tạo thành một cây chưa tất cả các đỉnh, so cho tổng trọng số các cạnh của cây là nhỏ nhất Thuật toán được tìm ra năm 1930 bởi nhà toán học Séc Vojtěch Jarník và sau đó bởi nhà nghiên cứu khoa học myas tính Robert C Prim năm 1975 và một lần nữa độc lập bởi Edsger Dijkstra năm
1959 Do đó nó được gọi là thuật toán DJP, thuật Jarník, hay thuật toán Prim– Jarník
2 Thuật toán tham lam
Một thuật toán tham lam, như tên gọi cua nó, đó là luôn luôn làm một sự lựa chọn tốt nhất tại thời điểm hiện tại Điều này có nghĩa rằng, sự lựa chọn tốt nhất ở mỗi bước sẽ dẫn tới lời giải tối ưu nhất
3 Cây khung nhỏ nhất
Theo lý thuyết đồ thị, chúng ta đều biết rằng 1 đồ thị được biểu diễn bằng công thức G=(V,E), trong đó đồ thị G của chúng ta bao gồm tập các đỉnh V và tập các cạnh E
Cây khung (spanning tree) của đồ thị là một tập hợp các cạnh của đồ thị thỏa mãn tập cạnh này không chứa chu trình và liên thông (từ một đỉnh bất
kì có thể đi tới bất kỳ đỉnh nào khác theo mà chỉ dùng các cạnh trên cây khung)
Trong đồ thị có trọng số, cây khung nhỏ nhất (minimum spanning tree) là cây khung có tổng trọng số các cạnh trong cây nhỏ nhất
Ví dụ về cây khung trong đồ thị vô hướng không trọng số:
Trang 5 Ví dụ về đồ thị có trọng số:
4 Mô tả thuật toán Prim
Thuật toán xuất phát từ một cây chỉ chưa đúng một đỉnh và mở rộng từng bước
Trang 6một, mỗi bước thêm một cạnh mới vào cây, cho tới khi bao trùm được tất cả các đỉnh của đồ thị
Dữ liệu vào: Một đồ thị có trọng số liên thông với tập hợp đỉnh V và tập hợp cạnh E ( trọng số có thể âm) Đồng thời cũng dùng V và E để ký hiệu
số đỉnh và số cạnh của đồ thị
Khởi tạo: V mới = {x}, trong đó x là một đỉnh bất kì (đỉnh bắt đầu) trong V,
E mới = {}
Lặp lại cho tới khi V mới = V:
Chọn cạnh (u, v) có trọng số nhỏ nhất thỏa mãn u thuộc V mới và v không thuộc V mới , và thêm cạnh (u, v) vào E mới
Thêm v vào V mới và thêm cạnh (u, v) và Emới
Dữ liệu ra: V mới và E mới là tập hợp đỉnh và tập hợp cạnh của một cây bao
trùm nhỏ nhất
Độ phức tạp tính toán
Một cách lập trình đơn giản sử dụng ma trận kề và tìm kiếm toàn bộ mảng
để tìm cạnh có trọng số nhỏ nhất có thời gian chạy O(V2) Bằng cách sử dụng cấu trúc dữ liệu đồng nhị phân và danh sách kề, có thể giảm thời gian chạy xuống O( E log V) Bằng cách sử dụng cấu trúc dữ liệu đồng Fibonanci phức tạp hơn, có thể giảm thời gian chạy xuống O(E + V log V), nhanh hơn thuật toán trước khi đồ thị có số cạnh E =ω(V)
Hình ảnh minh họa cho thuật toán Prim
Trang 7Đáp án của thuật toán là:
Ma trận đường đi: Trong bài toán hệ thống đường đi của dây điện Aij để đi từ phòng làm việc i đến phòng làm việc j, theo nội dung đã phân tích đường đi của dây điện chỉ bắt đầu từ 1 vài phòng và đi đến những phòng khác, kết hợp lại t có
ma trận đường đi sau: A11 A12 A13 … A1n
A21 A22 A13 … A2n
An1 An2 An3 … Ann
Ma trận A được gọi là ma trận đường đi của dây điện
Trang 813 24 22 13
13 19 22 14
13 19 19 13
14 22 19 13
III Giải thuật bài toán hệ thống dây điện áp dụng thuật toán Prim
1 Cài đặt thuật toán
- Viết bằng ngôn ngữ C++
- Ma trận kề của đồ thị
- Input: Ma trận kề file “input.txt”
- Output: Tính khoảng cách theo thuật toán Prim
2 Chương trình giải quyết bài toán hệ thống dây điện
#include<iostream>
#define MAX 100
using namespace std;
struct edg{
int dau, cuoi, h;
};
class dothi{
int n, c[MAX][MAX], ne, atree[MAX][MAX];
Trang 9edg graph[MAX], tree[MAX]; public:
int s;
bool chuaxet[MAX];
void readdata();
void init();
void treedfs(int u);
void bubblesort();
void prim(int s);
};
void dothi::readdata(){
FILE* f;
int i;
f=fopen("input.txt", "r"); if(f==NULL)
printf("Mo file co loi!"); fscanf(f,"%d", &n);
ne=0;
Trang 10for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) {
Trang 11fscanf(f, "%d", &c[i][j]);
if((c[i][j]!=0)&&(i<j)){ ne+ +;
graph[ne].dau=i;
graph[ne].cuoi=j;
graph[ne].h=c[i][j];
}
}
}
fclose(f);
cout << "Nhap dinh bat dau: ";
cin >> s;
}
void dothi::init()
{ for(int i=1; i<=n; i+
+)
chuaxet[i]=true;
}
void dothi::treedfs(int u){ //duyet tren cay chuaxet[u]=false;
Trang 12for(int i=1; i<=n; i++)
Trang 13if((atree[u][i]==1)&&(chuaxet[i]==true)) treedfs(i);
}
void dothi::bubblesort()
{ for(int i=1; i<ne; i++)
for(int j=ne; j>=i+1; j )
if(graph[j].h<graph[j-1].h)
swap(graph[j], graph[j-1]);
}
void dothi::prim(int s)
{ cout << endl;
for(int i = 1; i <= n; i++)
{ for(int j = 1; j <= n; j++) {
cout << c[i][j] << "\t"; }
cout << endl;
}
cout << endl;
int dH=0, net=0;
Trang 14for(int i=1; i<=n; i++)
Trang 15for(int j=1; j<=n; j++)
atree[i][j]=0;
bubblesort();
while(net!=n-1){
for(int i=1; i<=ne; i++){ //Moi lan lap while deu phai tim trong toan bo tap canh lay canh be nhat, 1 dau thuoc VH, 1 dau thuoc V
init();
treedfs(s);
int dau=graph[i].dau, cuoi=graph[i].cuoi;
if(chuaxet[dau]!=chuaxet[cuoi]){ //Canh i thoa man, bo sung vao cay khung be nhat
net++;
tree[net].dau=dau;
tree[net].cuoi=cuoi;
dH+=graph[i].h;
atree[dau][cuoi]=atree[cuoi][dau]=1;
break; //moi lan chi lay 1 canh
}
}
}
FILE* f;
Trang 16f=fopen("result.txt", "wt");
if(f==NULL)
printf("Mo file co loi!");
cout<<"Khoang cach: "<<dH<<endl;
cout << "Cach noi" << endl;
fprintf(f,"Khoang cach: %d\n",dH);
fprintf(f,"Cach noi\n");
for(int i=1; i<=net; i++) {
cout<<"Tu phong " << tree[i].dau<<" den phong "<<tree[i].cuoi<<endl; fprintf(f,"Phong %d den phong %d\n", tree[i].dau, tree[i].cuoi);
}
fclose(f);
}
int main()
{ dothi g;
g.readdata();
g.prim(g.s);
}
Tổ chức dữ liệu
- n: là biến cho biết số đỉnh của đồ thị
- c: là ma trận
Trang 17- ne: là số cạnh
- atree: là ma trận lưu trạng thái các cạnh
- grap đồ thị, tree là cây khung
- s: là đỉnh bắt đầu
- chuaxet[]: lưu trạng thái các đỉnh
- readdata(): phương thức đọc file
- init():phương thức khởi tạo
- treedfs(): phương thức duyệt cây
- bubblesort(): phương thức sắp xếp các cạnh
- prim(): phương thức prim
-dothi::readata(): Kết
quả chương trình
input.txt
Trang 18TỔNG KẾT
Thuật toán Prim được vận dụng để giải quyết bài toán hệ thống dây điện đã cho thấy trong thực tế các thuật toán rất cấp thiết và quan trọng trong hiện tại và tương lai Sử dụng các thuật toán để xử lý các vấn đề cách tối ưu nhất Qua bài toán về hệ thống dây điện này đã cho chúng em hiểu rất nhiều về môn học trí tuệ nhân tạo và vận dụng vào cuộc sống hàng ngày để sử lý một vấn đề nào đó Và đặc biệt là chúng em được tiếp thu mọi kiến thức được truyền đạt từ cô Đoàn Thị Thanh Hằng rất hay và
bổ ích Chúng em đã biết được cách tự lập thu thập nhiều thông tin bổ ích từ nhiều nguồn để hoàn thành bài tập lớn này Từ đó học được nhiều bài học ý nghĩa