MỤC LỤC
LỜI NĨI ĐẦU............................................................................................................. 3
I. Phân tích bài tốn........................................................................................................4
1. Phát biểu bài tốn...................................................................................................4
2. Mơ tả bài tố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 tốn Prim.............................................................................................6
III. Giải thuật bài tốn hệ thống dây điện áp dụng thuật toán Prim....................9
1. Cài đặt thuật tốn................................................................................................... 9
2. Chương trình giải quyết bài tốn hệ thống dây điện..............................................9
TỔNG KẾT................................................................................................................ 16
1
LỜ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 tốn trong khi việc giải bài tốn đó bằng cơng cụ khác của
tố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ì 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 tốn tìm đường đi ngắn nhất giữa các đỉnh của 1 đồ thị. Chẳng hạn bài tốn
tìm đường đi ngắn nhất giữa các thành phố, Bài tố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 tố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 tốn tìm đường đi ngắn nhất nên đã có nhiều
nhà tố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 tốn được đưa ra thì có thuật tốn Prim tìm cây khung nhỏ nhất.
I. Phân tích bài tốn
1. Phát biểu bài tố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 tốn bằng phương pháp tìm đường đi ngắn nhất – thuật
tốn Prim.
2. Mơ tả bài tố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ị hồ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 tốn hệ thống dây điện trở thành bài tốn tìm đường
đi ngắn nhất.
A
B
C
D
B
0
35
10
C
35
0
20
D
10
25
25
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 tốn Prim
1. Giới thiệu thuật tốn
Trong khoa học máy tính, thuật tốn Prim là một thuật tố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ó
tì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 tốn được tìm ra năm 1930
bởi nhà tố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 tốn DJP, thuật Jarník, hay thuật tốn Prim–
Jarník.
2. Thuật tốn tham lam
Một thuật tốn tham lam, như tên gọi cua nó, đó là ln ln 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ố:
• 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
mộ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: Vmới = {x}, trong đó x là một đỉnh bất kì (đỉnh bắt đầu) trong V,
Emới = {}
• Lặp lại cho tới khi Vmới = V:
Chọn cạnh (u, v) có trọng số nhỏ nhất thỏa mãn u thuộc Vmới và v
không thuộc Vmới, và thêm cạnh (u, v) vào Emới
Thêm v vào Vmới và thêm cạnh (u, v) và Emới
• Dữ liệu ra: Vmới và Emớ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 tốn
Một cách lập trình đơn giản sử dụng ma trận kề và tìm kiếm tồ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
Đá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
A=
… ……… …
An1 An2 An3 … Ann
Ma trận A được gọi là ma trận đường đi của dây điện
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
5
13 24 22 13
13 19 22 14
13 19 19 13
14 22 19 13
-
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 tốn Prim.
2. Chương trình giải quyết bài tố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];
edg 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;
for(int i = 1; i <= n; i++)
{ for(int j = 1; j <= n; j++)
{
fscanf(f, "%d", &c[i][j]);
if((c[i][j]!=0)&&(i
+;
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;
for(int i=1; i<=n; i++)
if((atree[u][i]==1)&&(chuaxet[i]==true))
treedfs(i);
}
void
dothi::bubblesort()
{ for(int i=1; i
for(int j=ne; j>=i+1; j--)
if(graph[j].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;
for(int i=1; i<=n; i++)
for(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;
f=fopen("result.txt", "wt");
if(f==NULL)
printf("Mo file co loi!");
cout<<"Khoang cach: "<
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 "<
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
-
-
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
result.txt
TỔ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ơ Đồ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 để hồn thành bài tập lớn này. Từ đó học được nhiều bài học ý nghĩa.