TRƯỜNG ĐẠI HỌC ĐIỆN LỰCKHOA CÔNG NGHỆ THÔNG TIN BÁO CÁO CHUYÊN ĐỀ HỌC PHẦN CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT NÂNG CAO ĐỀ TÀI: Thuật toán Dijkstra tìm đường đi ngắn nhất trên đồ thị Sinh viê
Trang 1TRƯỜNG ĐẠI HỌC ĐIỆN LỰC
KHOA CÔNG NGHỆ THÔNG TIN
BÁO CÁO CHUYÊN ĐỀ HỌC PHẦN CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT NÂNG CAO
ĐỀ TÀI:
Thuật toán Dijkstra tìm đường đi ngắn nhất trên đồ thị
Sinh viên thực hiện : CẤN QUANG TRIỀU
NGUYỄN THỊ THẢO MINH
Giảng viên hướng dẫn : NGUYỄN THỊ THANH TÂN
Hà Nội, tháng 06 năm 2020
Trang 3Mục lục
LỜI CẢM ƠN
LỜI NÓI ĐẦU
CHƯƠNG I : TỔNG QUAN VỀ THUẬT TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT
VÀ THUẬT TOÁN DIJKSTRA
1.Đường đi ngắn nhất trên đồ thị
2.Thuật toán Dijkstra
3.Giải thuật
4.Độ phức tạp
5.Lưu đồ thuật toán
CHƯƠNG II : BÀI TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT QUA NHIỀU ĐIỂM VÀ PHƯƠNG HƯỚNG GIẢI QUYẾT
1 Ý tưởng bài toán
2 Phương hướng giải quyết
3 Mô tả bài toán
CHƯƠNG III: GIỚI THIỆU VỀ GIAO DIỆN VÀ MÔ PHỎNG PHẦN
3.1 Cấu tạo
3.2 Source Code
Trang 4LỜI CẢM ƠN
Lời đầu tiên em xin chân thành cảm ơn các thầy cô trong Khoa Công NghệThông Tin Trường Đại Học Điện Lực đã trang bị cho em những kiến thức cơ bảncần thiết để em có thể thực hiện tốt báo cáo chuyên đề này
Trong thời gian làm báo cáo môn học, em đã nhận được nhiều sự giúp đỡ,đóng góp ý kiến và chỉ bảo nhiệt tình của thầy cô, gia đình và bạn bè Em xin chânthành cảm ơn cô giáo Nguyễn Thị Thanh Tân đã tận tình giúp đỡ, hướng dẫn vàchỉ bảo em trong suốt quá trình học tập, nghiên cứu
Mặc dù em đã có sự cố gắng, nhưng trong khoảng thời gian cho phép cũng như hạn chế về kiến thức nên Báo cáo chuyên đề này của em không thể tránh khỏi những kiến thức thiếu sót Chính vì vậy, em rất mong nhận được sự góp ý của các thầy cô giáo và bạn bè
Chúng em xin chân thành cảm ơn quý thầy cô giáo!
Hà Nội, ngày 31 tháng 6 năm 2020 Giảng viên hướng dẫn Sinh viên thực hiện
Nguyễn Thị Thảo Minh
Trang 5LỜI NÓI ĐẦU
Ngày nay, cùng với sự phát triển của đất nước ngành Công nghệ thông tin đã có những bước phát triển mạnh mẽ không ngừng và tin học đã trở thành chiếc chìa khóa dẫn đến thành công cho nhiều cá nhân trong nhiều lĩnh vực, hoạt động Công nghệ thông tin là ngành sử dụng máy tính và phần mềm máy tính để chuyển đổi, lưu trữ, bảo vệ, xử lý, truyền, và thu thập thông tin
Trên thế giới cũng như ở Việt Nam, công nghê thông tin đã trở thành một ngành công nghệ mũi nhọn, nó là một ngành khóa học kỹ thuật không thể thiếu trong việc áp dụng vào các hoạt động xã hội như: Quản lý, kinh tế, thông tin…
Trong khoa học máy tính và trong toán học, thuật toán tìm đường đi ngắn nhất trong đồ thị là một bài toán thường được vận dụng trong các ứng dụng tin học,
và là một yêu cầu không thể thiếu trong khi thiết kế các phần mềm như xây dựng bản đồ mạng lưới giao thông
Mặc dù rất cố gắng để hoàn thành đề tài, xong thời gian có hạn và kiến thức còn hạn hẹp nên bài báo cáo của chúng em còn nhiều thiếu xót cần bổ sung Vì vậy, chúng em mong nhận được ý kiến đóng góp của thầy cô và bạn bè để đề tài này ngày càng hoàn thiện tốt hơn
Cuối cùng, chúng em xin chân thành cảm ơn cô Nguyễn Thị Thanh Tân giảng viên bộ môn Cấu trúc dữ liệu và Giải thuật nâng cao đã tận tình chỉ bảo hướng dẫn chúng em hoàn thành đề tài nay
Trang 6CHƯƠNG I : TỔNG QUAN VỀ THUẬT TOÁN TÌM ĐƯỜNG ĐI
NGẮN NHẤT DIJKSTRA
1.Đường đi ngắn nhất trên đồ thị
Nếu đồ thị biểu diễn một mạng lưới giao thông, thì người ta không chỉ quan tâm tới việc có tồn tại đường đi từ một đỉnh này tới đỉnh khác hay không, mà người ta còn quan tâm tới con đường tối ưu nhất, ngắn nhất có thể
Trong lý thuyết đồ thị, bài toán đường đi ngắn nhất giữa hai đỉnh cho trước là bài toán tìm một đường đi giữa chúng sao cho tổng các trọng số của các cạnh tạo nên đường đi đó là nhỏ nhất Định nghĩa một cách hình thức, cho trước một đồ thị có trọng số G=(V,E,w)G=(V,E,w) (nghĩa là một tập đỉnh V, một tập cạnh E, và một hàm trọng số có giá trị thực w : E → R), cho trước một đỉnh u thuộc V, tìm một đường đi P từ u tới một đỉnh v thuộc V sao cho:
∑p∈Pw(p)nhỏ nhất trong tất cả các đường đi từ u tới v Bài toán đường đi ngắn nhất giữa mọicặp đỉnh là một bài toán tương tự, trong đó ta phải tìm các đường đi ngắn nhất cho mọi cặp đỉnh u và v
Các thuật toán thường được dùng để giải quyết những bài toán này là:
Thuật toán Dijkstra - giải bài toán bài toán đường đi ngắn nhất giữa hai đỉnh cho trước nếu tất cả các trọng số đều không âm Thuật toán này có thể tính toán tất cả các đường đi ngắn nhất từ một đỉnh xuất phát cho trước s tới mọi đỉnh khác mà không làm tăng thời gian chạy
Thuật toán Bellman-Ford - giải bài toán bài toán đường đi ngắn nhất giữa hai đỉnh cho trước trong trường hợp trọng số có thể có giá trị âm
Giải thuật tìm kiếm A* giải bài toán bài toán đường đi ngắn nhất giữa hai đỉnh cho trước sử dụng heuristics để tăng tốc độ tìm kiếm
Trang 7 Thuật toán Floyd-Warshall - giải bài toán đường đi ngắn nhất cho mọi cặp đỉnh.
Thuật toán Johnson - giải bài toán đường đi ngắn nhất cho mọi cặp đỉnh, có thể nhanh hơn thuật toán Floyd-Warshall trên các đồ thị thưa
Lý thuyết nhiễu (Perturbation theory) - tìm đường đi ngắn nhất địa phương (trong trường hợp xấu nhất)
2.Thuật toán Dijkstra
Thuật toán Dijkstra, mang tên của nhà khoa học máy tính người Hà Lan Edsger Dijkstra vào năm 1956 và ấn bản năm 1959
Trong trường hợp đồ thị G=(V,E,w)G=(V,E,w) có trọng số trên các cạnh không
âm, ta có thuật toán Dijkstra để tìm đường đi ngắn nhất từ đỉnh xuất phát s tới các đỉnh khác của đồ thị
Thuật toán thường được sử dụng trong định tuyến với một chương trình con trong các thuật toán đồ thị hay trong công nghệ Hệ thống định vị toàn cầu (GPS)
3.Giải thuật
Thuật toán có thể được mô tả bằng thủ tục Dijkstra như sau:
-Bước khởi tạo: s là đỉnh xuất phát
Trang 8-Bước trả về kết quả : Return(d (s , t) );
*Sau đây là các bước của giải thuật Dijkstra:
B1 Khởi tạo: Đặt kv:= false v V; dv:= ,v V \ {a}, d a:=0
B2. Chọn v V sao cho k v = false và d v = min {d t / t V, k t = false}
Nếu d v = thì kết thúc, không tồn tại đường đi từ a đến b.
B3. Đánh dấu đỉnh v, k v: = true.
B4. Nếu v = b thì kết thúc và d b là độ dài đường đi ngắn nhất từ a đến b.
Ngược lại nếu v b sang B5.
B5 Với mỗi đỉnh u kề với v mà k u = false, kiểm tra
Nếu d u > d v + w(v,u) thì d u := d v + w(v,u)
Ghi nhớ đỉnh v: p u := v Quay lại B2.
4 Độ phức tạp
Thuật toán Dijkstra bình thường sẽ có độ phức tạp là O(n2+m)O(n2+m), do ta phảiduyệt n lần (đối với n đỉnh), mỗi lần duyệt lại phải duyệt qua n đỉnh để tìm đỉnh cókc[u] nhỏ nhất Tuy nhiên ta có thể sử dụng kết hợp với cấu trúc heap hoặc set, khi
đó độ phức tạp sẽ là O((m+n)log(n))O((m+n)log(n)), nếu dùng Fibonacci thì độphức tạp giảm xuống còn O(m+nlogn)O(m+nlogn) Trong đó m là số cạnh, n là sốđỉnh của đồ thị đang xét
5.Lưu đồ thuật toán
Trang 9Chương II : BÀI TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT QUA
NHIỀU ĐIỂM VÀ PHƯƠNG HƯỚNG GIẢI QUYẾT
1 Ý tưởng bài toán
Trang 10Ta có mảng kc[u] là khoảng cách ngắn nhất từ đỉnh s tới đỉnh u trên đồ thị Ban đầu kc[s] = 0, các giá trị khác bằng dương vô cực Ta sẽ lấy đỉnh u có kc[u] nhỏ nhất vào thời điểm hiện tại, và sử dụng khoảng cách của nó để cập nhật
khoảng cách ngắn nhất của các đỉnh xung quanh Với một đỉnh u bất kì, vì nó đượccập nhật bởi các đường đi ngắn nhất của các đỉnh xung quanh nó, nên bản thân đường đi của nó cũng là ngắn nhất
2 Phương hướng giải quyết
B1: Lấy thông tin điểm gốc và các điểm đến.
B2: Sử dụng thuật toán Dijkstra để tìm đường đi từ gốc đến các điểm lân
cận
B3: Sắp xếp các điểm theo chi phí và tìm điểm cần đến có chi phí nhỏ nhất.
B4: Kiểm tra xem còn điểm cần đến hay không? Nếu còn, thay điểm gốc
bằng điểm cần đến có chi phí nhỏ nhất và lặp lại B2 (Đệ quy)
B5: Lấy lại đường đi từ điểm gốc đến các điểm đến, sử dụng các thuật toán
đồ họa máy tính để vẽ đường đi lên bản đồ
3 Mô tả bài toán
Nguyên lý tối ưu là nếu tồn tại một đường đi ngắn nhất từ đỉnh I đến đỉnh J
và đỉnh K nằm trên con đường đi này thì ta phải có các đường đi từ đỉnh I đến đỉnh
K và đường đi từ đỉnh K đến đỉnh J là những đường đi ngắn nhất
Trong các giải thuật sau, ta dùng ma trận có chiều dài L để chứa chiều dài các cung, chiều dài cung là một số không âm ( lớn hơn hay bằng 0 ) ta có:
L[ i , j ] : = 0 với mọi i = 1,2 …, n
L[ i , j ] : > 0 nếu tồn tại một cung từ đỉnh A đến đỉnh B
L[ i , j ] = vô cực nếu không tồn tại một cung từ đỉnh I đến đỉnh J
Trang 11CHƯƠNG III: GIỚI THIỆU VỀ GIAO DIỆN VÀ MÔ PHỎNG
PHẦN MỀM
1.Ngôn ngữ sử dụng
-Java (phiên âm Tiếng Việt: "Gia-va") là một ngôn ngữ lập trình hướng đối
tượng (OOP) và dựa trên các lớp (class) Khác với phần lớn ngôn ngữ lập trình thông thường, thay vì biên dịch mã nguồn thành mã máy hoặc thông dịch mã nguồn khi chạy, Java được thiết kế để biên dịch mã nguồn thành bytecode,
bytecode sau đó sẽ được môi trường thực thi (runtime environment) chạy
-Java được vay mượn nhiều từ C & C++ nhưng có cú pháp hướng đối tượng đơn
giản hơn và ít tính năng xử lý cấp thấp hơn Do đó việc viết một chương trình bằngJava dễ hơn, đơn giản hơn, đỡ tốn công sửa lỗi hơn Nhưng về lập trình hướng đối tượng thì Java phức tạp hơn
-Giới thiệu về Swing Java Foundation Classes (JFC) được được giới thiệu trong
phiên bản 2.0 (Java Development Kit – JDK 2.0), là một framework hỗ trợ lập trình giao diện đồ hoạ (Graphical Interface) với thư viện Swing
-Swing là một framework được thiết kế theo mô hình MVC (Model View
Controller), hỗ trợ công nghệ gọi là “Pluggable-Look-And-Feel” cho phép các thành phần giao diện có thể được hiển thị trên bất ký hệ điều hành nào như
Windows, Mac OS, Linux, …
2.Hướng dẫn sử dụng
Giao diện chính:
Trang 12 Cách sử dụng:
Nhấn vào nút chọn OpenFile và chọn tới file dữ liệu cần tính toán.
Nhấn vào nút LoadFile để mở file
Chọn hai đỉnh muốn tính đường đi và ấn tính.
Có hai nút tính: RunStep và RunAll
+RunStep : tính đường đi từ 1 điểm đến 1 điểm nào đó của đồ thị
+RunAll: tính đường đi từ 1 điểm đến mọi điểm trên đồ thị
Kết quả tính toán sẽ hiển thị trong bảng LogAll và LogStep.
Nếu muốn xóa toàn bộ dữ liệu đã load vào từ file và kết quả tính toán Chọn nút Reset
Ấn ‘Thoát’ để thoát chương trình.
3.Cấu tạo chương trình
3.1 Cấu tạo
Chương trình được cấu tạo từ 3 package : UI, Logic, Main
Trang 13-UI: Là package dùng để xây dựng giao diện và xử lí các yêu cầu mà người dùng thao tác, gồm 5 class.
+Class chính : DijkstraPanel.java-Logic: là package dùng để thực hiện chức năng tìm đường đi ngắn nhất và lưu trữ ma trận trọng số được load vào chương trình.
+Class chính : Dijkstra.java -Main: là package dùng để bắt đầu chương trình
+Class chính : Main.java 3.2 Source Code
a Class DijkstraPanel.java
Trang 14Phương thức addComp() : Tạo giao diện chương trình
@Override
public void addComp() {
Font f = new Font( "Tahoma" , Font.BOLD, 15);
Font fs = new Font( "Tahoma" , Font.PLAIN, 20);
add( menuBar );
loadFile = createLabel( fs , "File:" , menuBar getX(), menuBar getY()
btOpen = createButton( fs , "Open File" , tfFile getX() +
add( btOpen );
btFile = createButton( fs , "Load File" , btOpen getX() +
Color.MAGENTA, BT_LOAD_FILE);
add( btFile );
choi = new Choice();
choi setBounds( btFile getX() + btFile getWidth() + 20,
choi add( "Begin" );
Trang 15choi1 setBounds( btFile getX() + btFile getWidth() + 20,
choi1 add( "End" );
btRunAll = createButton( f , "Run All" , 0, 0, Color.BLACK,
btRunStep = createButton( f , "Run Step" , 0, 0, Color.BLACK,
JPanel panelTinh = new JPanel(new GridLayout(1, 3, 30, 10));
panelTinh setBorder(new TitledBorder( "Tính Đường Đi" ));
panelTinh setSize(GUI.WIDTH_FRAME / 2 - 100, 50);
panelTinh setLocation( btFile getX() + btFile getWidth() + 20,
panelTinh add( choi );
panelTinh add( choi1 );
panelTinh add( btRunStep );
panelTinh add( btRunAll );
add( panelTinh );
table setFont( f );
JScrollPane jScrollPane = new JScrollPane( table );
jScrollPane setSize(GUI.WIDTH_FRAME / 2 - 50, GUI.HEIGHT_FRAME / 2);
jScrollPane setLocation( loadFile getX() + 10, loadFile getY() +
add( jScrollPane );
JPanel paneltb = new JPanel();
titletb = createLabel( fs , "Ma Trận" , 0, 0, Color.BLACK);
paneltb setSize( jScrollPane getWidth(), 50);
paneltb setLocation( jScrollPane getX(), jScrollPane getY() - 30);
paneltb add( titletb );
JScrollPane scroll = new JScrollPane( textAll );
JPanel panelRunAll = new JPanel(new BorderLayout());
panelRunAll setBorder(new TitledBorder( "Log All" ));
panelRunAll add( scroll , BorderLayout.PAGE_START);
panelRunAll setLocation( paneltb getX() + paneltb getWidth() + 20,
paneltb getY());
panelRunAll setSize(GUI.WIDTH_FRAME / 2 - 10, GUI.HEIGHT_FRAME / 2 + 40);
add( panelRunAll );
Trang 16btReset = createButton( fs , "Reset" , panelRunAll getX() +
panelRunAll getWidth() / 2 - 100,
panelRunAll getY() + panelRunAll getHeight() + 10, Color.blue, BT_RESET);
add( btReset );
btThoat = createButton( fs , "Thoát" , btReset getX() +
add( btThoat );
textLog = new JTextArea( "Path: " );
JScrollPane scrollPath = new JScrollPane( textLog );
JPanel panelketqua = new JPanel(new BorderLayout());
panelketqua setBorder(new TitledBorder( "Log Step" ));
panelketqua add( scrollPath , BorderLayout.PAGE_START);
panelketqua setLocation( jScrollPane getX(), jScrollPane getY() +
protected void clickComps(String name ) {
JFileChooser fc = new JFileChooser();
int select = fc showOpenDialog(this);
int rs = JOptionPane.showConfirmDialog(this, "Bạn có muốn
JOptionPane.YES_NO_OPTION);
if ( rs == JOptionPane.YES_OPTION) {
System.exit(1);
Trang 17} else {
return; }
break;
default:
break; }
}
-Phương thức reset(): Cài lại chương trình
private void reset() {
-Phương thức actionRunAll() và actionRunStep(): Xử lí tính toán
private void actionRunAll() {
}
private void actionRunStep() {
int item = choi getSelectedIndex();
if ( choi getSelectedItem() == "Begin" || choi1 getSelectedItem()
JOptionPane.showMessageDialog(this, "Chưa chọn điểm đầu or
} else {
} }
-Phương thức actionLoad(): Mở File được Open lên
private void actionLoad() {
JOptionPane.showMessageDialog(this, "Chọn File !!!" );
} else {
for (int = 0; i < distra getSoDinh(); i ++) {
Trang 18choi add( i + 1 + "" );
choi1 add( i + 1 + "" );
} loadMatrix();
} }
-Phương thức loadMatrix(): Xử lí ma trận trọng số
private void loadMatrix() {
int [][] = distra getG();
int infinity = 0;
int col = 1;
head = new String[ a length ];
data = new String[ a [0] length ][ a length ];
for (int = 1; i <= a length ; i ++) {
head [ - 1] = String.valueOf(i );
for (int = 1; j <= a length ; j ++) {
if ( a i - 1][ j - 1] == infinity ) {
data [ - 1][ j - 1] = "∞" ; } else {
data [ - 1][ j - 1] = String.valueOf(a i - 1][ j 1]);
-} }
} DefaultTableModel model = new DefaultTableModel( data , head );
System.out.println( table getColumnCount());
if ( table getColumnCount() > col ) {
for (int = 0; i < head length ; i ++) {
TableColumn tc = table getColumnModel().getColumn( i );
b Class dijsktra.java : Đối tượng xử lí thuật toán
Trang 19-Phương thức getDuLieuTuFile(): Đọc dữ liệu từ file ra
public boolean getDuLieuTuFile(String tenfile ) {
String path = tenfile ;
try {
File file = new File( path );
if (! file exists()) {
return false; }
FileInputStream input = new FileInputStream( path );
InputStreamReader istream = new InputStreamReader( input ); BufferedReader reader = new BufferedReader( istream ); String sc ;
// doc so dinh cua do thi , dinh bat dau , dinh dich