Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 25 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
25
Dung lượng
290,69 KB
Nội dung
TRƯỜ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 ngắn đồ thị Sinh viên thực : 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 Ngành : CÔNG NGHỆ THÔNG TIN Chuyên ngành : CÔNG NGHỆ PHẦN MỀM Lớp : D13-CNPM3 Khóa : 2018-2022 Hà Nội, tháng 06 năm 2020 PHIẾU CHẤM ĐIỂM Sinh viên thực hiện: ST T Họ tên sinh viên Cấn Quang Triều Nguyễn Thị Thảo Minh Nội dung thực Điểm Chữ kí Giảng viên chấm: Họ tên Giảng viên chấm : Giảng viên chấm : Chữ ký Ghi Mục lục LỜI CẢM ƠN LỜI NĨI ĐẦU CHƯƠNG I : TỔNG QUAN VỀ THUẬT TỐN TÌM ĐƯỜNG ĐI NGẮN NHẤT VÀ THUẬT TỐN DIJKSTRA 1.Đường ngắ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 TỐN TÌM ĐƯỜNG ĐI NGẮN NHẤT QUA NHIỀU ĐIỂM VÀ PHƯƠNG HƯỚNG GIẢI QUYẾT Ý tưởng tốn Phương hướng giải Mơ tả tốn CHƯƠ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 2.Hướng dẫn sử dụng Giao diện Cách sử dụng 3.Cấu tạo chương trình 3.1 Cấu tạo 3.2 Source Code LỜI CẢM ƠN Lời em xin chân thành cảm ơn thầy cô Khoa Công Nghệ Thông Tin Trường Đại Học Điện Lực trang bị cho em kiến thức cần thiết để em thực tốt báo cáo chuyên đề Trong thời gian làm báo cáo môn học, em nhận nhiều giúp đỡ, đóng góp ý kiến bảo nhiệt tình thầy cơ, gia đình bạn bè Em xin chân thành cảm ơn cô giáo Nguyễn Thị Thanh Tân tận tình giúp đỡ, hướng dẫn bảo em suốt trình học tập, nghiên cứu Mặc dù em có cố gắng, khoảng thời gian cho phép hạn chế kiến thức nên Báo cáo chuyên đề em tránh khỏi kiến thức thiếu sót Chính vậy, em mong nhận góp ý thầy giáo 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 năm 2020 Giảng viên hướng dẫn Sinh viên thực Nguyễn Thị Thanh Tân Cấn Quang Triều Nguyễn Thị Thảo Minh LỜI NÓI ĐẦU Ngày nay, với phát triển đất nước ngành Cơng nghệ thơng tin có bước phát triển mạnh mẽ không ngừng tin học trở thành chìa khóa dẫn đến thành cơng cho nhiều cá nhân nhiều lĩnh vực, hoạt động Cơng nghệ thơng tin ngành sử dụng máy tính phần mềm máy tính để chuyển đổi, lưu trữ, bảo vệ, xử lý, truyền, thu thập thông tin Trên giới Việt Nam, công nghê thông tin trở thành ngành công nghệ mũi nhọn, ngành khóa học kỹ thuật khơng thể thiếu việc áp dụng vào hoạt động xã hội như: Quản lý, kinh tế, thông tin… Trong khoa học máy tính tốn học, thuật tốn tìm đường ngắn đồ thị toán thường vận dụng ứng dụng tin học, yêu cầu thiếu thiết kế phần mềm xây dựng đồ mạng lưới giao thông Mặc dù cố gắng để hồn thành đề tài, xong thời gian có hạn kiến thức hạn hẹp nên báo cáo chúng em cịn nhiều thiếu xót cần bổ sung Vì vậy, chúng em mong nhận ý kiến đóng góp thầy bạn bè để đề tài ngày hoàn thiện tốt 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 môn Cấu trúc liệu Giải thuật nâng cao tận tình bảo hướng dẫn chúng em hoàn thành đề tài CHƯƠNG I : TỔNG QUAN VỀ THUẬT TỐN TÌM ĐƯỜNG ĐI NGẮN NHẤT DIJKSTRA 1.Đường ngắn đồ thị Nếu đồ thị biểu diễn mạng lưới giao thông, người ta khơng quan tâm tới việc có tồn đường từ đỉnh tới đỉnh khác hay khơng, mà người ta cịn quan tâm tới đường tối ưu nhất, ngắn Trong lý thuyết đồ thị, toán đường ngắn hai đỉnh cho trước tốn tìm đường chúng cho tổng trọng số cạnh tạo nên đường nhỏ Định nghĩa cách hình thức, cho trước đồ thị có trọng số G=(V,E,w)G=(V,E,w) (nghĩa tập đỉnh V, tập cạnh E, hàm trọng số có giá trị thực w : E → R), cho trước đỉnh u thuộc V, tìm đường P từ u tới đỉnh v thuộc V cho: ∑p∈Pw(p) nhỏ tất đường từ u tới v Bài toán đường ngắn cặp đỉnh toán tương tự, ta phải tìm đường ngắn cho cặp đỉnh u v Các thuật toán thường dùng để giải toán là: • Thuật tốn Dijkstra - giải tốn toán đường ngắn hai đỉnh cho trước tất trọng số không âm Thuật tốn tính tốn tất đường ngắn từ đỉnh xuất phát cho trước s tới đỉnh khác mà không làm tăng thời gian chạy • Thuật tốn Bellman-Ford - giải toán toán đường ngắn hai đỉnh cho trước trường hợp trọng số có giá trị âm • Giải thuật tìm kiếm A* giải toán toán đường ngắn hai đỉnh cho trước sử dụng heuristics để tăng tốc độ tìm kiếm • Thuật tốn Floyd-Warshall - giải tốn đường ngắn cho cặp đỉnh • Thuật toán Johnson - giải toán đường ngắn cho cặp đỉnh, nhanh thuật tốn Floyd-Warshall đồ thị thưa • Lý thuyết nhiễu (Perturbation theory) - tìm đường ngắn đị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 nhà khoa học máy tính người Hà Lan Edsger Dijkstra vào năm 1956 ấn năm 1959 Trong trường hợp đồ thị G=(V,E,w)G=(V,E,w) có trọng số cạnh khơng âm, ta có thuật tốn Dijkstra để tìm đường ngắn từ đỉnh xuất phát s tới đỉnh khác đồ thị Thuật toán thường sử dụng định tuyến với chương trình thuật tốn đồ thị hay cơng nghệ Hệ thống định vị tồn cầu (GPS) 3.Giải thuật Thuật tốn mơ tả thủ tục Dijkstra sau: -Bước khởi tạo: s đỉnh xuất phát for v thuộc V { d[v] = A[s,v]; truoc[v] =s; } -Bước lặp: While(V≠rỗng){ ; ; V = V\{u}; for v thuộc V { if (d[v]> d[u] +A[u,v]) { d[v] = d[u] +A[u,v]; truoc[v] = u; } } } -Bước trả kết : Return(d (s , t) ); *Sau bước giải thuật Dijkstra: B1 Khởi tạo: Đặt kv:= false ∀v ∈ V; dv:= ∞,∀v ∈ V \ {a}, da:=0 B2 Chọn v ∈ V cho kv = false dv = {dt / t∈ V, kt = false} Nếu dv = ∞ kết thúc, không tồn đường từ a đến b B3 Đánh dấu đỉnh v, kv:= true B4 Nếu v = b kết thúc db độ dài đường ngắn từ a đến b Ngược lại v ≠ b sang B5 B5 Với đỉnh u kề với v mà ku = false, kiểm tra Nếu du > dv + w(v,u) du:= dv + w(v,u) Ghi nhớ đỉnh v: pu:= v Quay lại B2 Độ phức tạp Thuật tốn Dijkstra bình thường có độ phức tạp O(n2+m)O(n2+m), ta phải duyệt n lần (đối với n đỉnh), lần duyệt lại phải duyệt qua n đỉnh để tìm đỉnh có kc[u] nhỏ Tuy nhiên ta sử dụng kết hợp với cấu trúc heap set, độ phức tạp O((m+n)log(n))O((m+n)log(n)), dùng Fibonacci độ phức tạp giảm xuống cịn O(m+nlogn)O(m+nlogn) Trong m số cạnh, n số đỉnh đồ thị xét 5.Lưu đồ thuật toán Begin n, C = (cij), a, z ≤ ∈ L(z) S Đ ∈ S ∈ Đ L(x) = min(L(x), L(v) + c(v,x)) End Chương II : BÀI TỐN TÌM ĐƯỜNG ĐI NGẮN NHẤT QUA NHIỀU ĐIỂM VÀ PHƯƠNG HƯỚNG GIẢI QUYẾT Ý tưởng toán Ta có mảng kc[u] khoảng cách ngắn từ đỉnh s tới đỉnh u đồ thị Ban đầu kc[s] = 0, giá trị khác dương vô cực Ta lấy đỉnh u có kc[u] nhỏ vào thời điểm tại, sử dụng khoảng cách để cập nhật khoảng cách ngắn đỉnh xung quanh Với đỉnh u bất kì, cập nhật đường ngắn đỉnh xung quanh nó, nên thân đường ngắn Phương hướng giải B1: Lấy thông tin điểm gốc điểm đến B2: Sử dụng thuật toán Dijkstra để tìm đường từ gốc đến điểm lân cận B3: Sắp xếp điểm theo chi phí tìm điểm cần đến có chi phí nhỏ B4: Kiểm tra xem cịn điểm cần đến hay khơng? Nếu cịn, thay điểm gốc điểm cần đến có chi phí nhỏ lặp lại B2 (Đệ quy) B5: Lấy lại đường từ điểm gốc đến điểm đến, sử dụng thuật tốn đồ họa máy tính để vẽ đường lên đồ Mô tả toán Nguyên lý tối ưu tồn đường ngắn từ đỉnh I đến đỉnh J đỉnh K nằm đường ta phải có đường từ đỉnh I đến đỉnh K đường từ đỉnh K đến đỉnh J đường ngắn Trong giải thuật sau, ta dùng ma trận có chiều dài L để chứa chiều dài cung, chiều dài cung số không âm ( lớn hay ) ta có: L[ i , j ] : = với i = 1,2 …, n L[ i , j ] : > tồn cung từ đỉnh A đến đỉnh B L[ i , j ] = vô cực không tồn cung từ đỉnh I đến đỉnh J CHƯƠ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") ngơn ngữ lập trình hướng đối tượng (OOP) dựa lớp (class) Khác với phần lớn ngơn ngữ lập trình thơng thường, thay biên dịch mã nguồn thành mã máy thông dịch mã nguồn chạy, Java thiết kế để biên dịch mã nguồn thành bytecode, bytecode sau mơi trường thực thi (runtime environment) chạy -Java vay mượn nhiều từ C & C++ có cú pháp hướng đối tượng đơn giản tính xử lý cấp thấp Do việc viết chương trình Java dễ hơn, đơn giản hơn, đỡ tốn công sửa lỗi Nhưng lập trình hướng đối tượng Java phức tạp -Giới thiệu Swing Java Foundation Classes (JFC) được giới thiệu phiên 2.0 (Java Development Kit – JDK 2.0), framework hỗ trợ lập trình giao diện đồ hoạ (Graphical Interface) với thư viện Swing -Swing framework thiết kế theo mơ hình MVC (Model View Controller), hỗ trợ công nghệ gọi “Pluggable-Look-And-Feel” cho phép thành phần giao diện hiển thị bất ký hệ điều hành Windows, Mac OS, Linux, … 2.Hướng dẫn sử dụng Giao diện chính: Cách sử dụng: • Nhấn vào nút chọn OpenFile chọn tới file liệu cần tính tốn • Nhấn vào nút LoadFile để mở file • Chọn hai đỉnh muốn tính đường ấn tính • Có hai nút tính: RunStep RunAll +RunStep : tính đường từ điểm đến điểm đồ thị +RunAll: tính đường từ điểm đến điểm đồ thị • Kết tính tốn hiển thị bảng LogAll LogStep • Nếu muốn xóa toàn liệu load vào từ file kết tính tốn Chọn nút Reset • Ấn ‘Thố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ấu tạo từ package : UI, Logic, Main -UI: Là package dùng để xây dựng giao diện xử lí yêu cầu mà người dùng thao tác, gồm class +Class : DijkstraPanel.java -Logic: package dùng để thực chức tìm đường ngắn lưu trữ ma trận trọng số load vào chương trình +Class : Dijkstra.java -Main: package dùng để bắt đầu chương trình +Class : Main.java 3.2 Source Code a Class DijkstraPanel.java Phươ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); fileMenu.setFont(f); helpMenu.setFont(f); fileMenu.add(createMenuItem("New", KeyEvent.VK_N, Event.CTRL_MASK)); fileMenu.add(createMenuItem("Open", KeyEvent.VK_O, Event.CTRL_MASK)); fileMenu.add(createMenuItem("Save", KeyEvent.VK_S, Event.CTRL_MASK)); fileMenu.add(createMenuItem("Exit", KeyEvent.VK_X, Event.CTRL_MASK)); helpMenu.add(createMenuItem("Help", KeyEvent.VK_H, Event.CTRL_MASK)); helpMenu.add(createMenuItem("About", KeyEvent.VK_A, Event.CTRL_MASK)); menuBar = new JMenuBar(); menuBar.setSize(100, 30); menuBar.setBackground(Color.GRAY); menuBar.add(fileMenu); menuBar.add(helpMenu); menuBar.setLocation(10, 10); add(menuBar); loadFile = createLabel(fs, "File:", menuBar.getX(), menuBar.getY() + menuBar.getHeight() + 20, Color.RED); add(loadFile); tfFile = createTextField(fs, loadFile.getX() + loadFile.getWidth() + 10, loadFile.getY() - 3, GUI.WIDTH_FRAME / - 300, Color.BLACK); add(tfFile); btOpen = createButton(fs, "Open File", tfFile.getX() + tfFile.getWidth() + 5, loadFile.getY() - 3, Color.ORANGE, BT_OPEN); add(btOpen); btFile = createButton(fs, "Load File", btOpen.getX() + btOpen.getWidth() + 5, loadFile.getY() - 3, Color.MAGENTA, BT_LOAD_FILE); add(btFile); choi = new Choice(); choi.setBounds(btFile.getX() + btFile.getWidth() + 20, btFile.getY(), 200, 30); choi.add("Begin"); choi1 = new Choice(); choi1.setBounds(btFile.getX() + btFile.getWidth() + 20, btFile.getY(), 200, 30); choi1.add("End"); btRunAll = createButton(f, "Run All", 0, 0, Color.BLACK, BT_RUN_ALL); btRunStep = createButton(f, "Run Step", 0, 0, Color.BLACK, BT_RUN_STEP); JPanel panelTinh = new JPanel(new GridLayout(1, 3, 30, 10)); panelTinh.setBorder(new TitledBorder("Tính Đường Đi")); panelTinh.setSize(GUI.WIDTH_FRAME / - 100, 50); panelTinh.setLocation(btFile.getX() + btFile.getWidth() + 20, btFile.getY()); panelTinh.add(choi); panelTinh.add(choi1); panelTinh.add(btRunStep); panelTinh.add(btRunAll); add(panelTinh); table = new JTable(); table.setBackground(Color.WHITE); table.setForeground(Color.BLUE); table.setFont(f); JScrollPane jScrollPane = new JScrollPane(table); jScrollPane.setSize(GUI.WIDTH_FRAME / - 50, GUI.HEIGHT_FRAME / 2); jScrollPane.setLocation(loadFile.getX() + 10, loadFile.getY() + loadFile.getHeight() + 60); add(jScrollPane); model = new DefaultTableModel(); table.setModel(model); 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); add(paneltb); textAll = new JTextArea("Path:"); textAll.setRows(20); textAll.setLineWrap(true); textAll.setColumns(1); textAll.setWrapStyleWord(true); 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 / - 10, GUI.HEIGHT_FRAME / + 40); add(panelRunAll); // // btReset = createButton(fs, "Reset", panelRunAll.getX() + panelRunAll.getWidth() / - 100, panelRunAll.getY() + panelRunAll.getHeight() + 10, Color.blue, BT_RESET); add(btReset); btThoat = createButton(fs, "Thoát", btReset.getX() + btReset.getWidth() + 20, btReset.getY(), Color.GREEN, BT_THOAT); add(btThoat); textLog = new JTextArea("Path: "); textLog.setRows(3); textLog.setEditable(false); 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() + jScrollPane.getHeight() + 70); panelketqua.setSize(GUI.WIDTH_FRAME - 50, 85); add(panelketqua); } -Phương thức clickComps(): Xử lí kiện chương trình @Override protected void clickComps(String name) { distra = new dijkstra(); switch (name) { case BT_LOAD_FILE: actionLoad(); break; case BT_RUN_ALL: actionRunAll(); break; case BT_OPEN: JFileChooser fc = new JFileChooser(); int select = fc.showOpenDialog(this); if (select == 0) { tfFile.setText(fc.getSelectedFile().getPath()); // System.out.println(tfFile.getText()); } break; case BT_RUN_STEP: actionRunStep(); break; case BT_RESET: reset(); break; case BT_THOAT: int rs = JOptionPane.showConfirmDialog(this, "Bạn có muốn không?", "Thông báo", JOptionPane.YES_NO_OPTION); if (rs == JOptionPane.YES_OPTION) { System.exit(1); } else { return; } break; default: break; } } -Phương thức reset(): Cài lại chương trình private void reset() { choi.removeAll(); choi.add("Begin"); choi1.removeAll(); choi1.add("End"); tfFile.setText(""); DefaultTableModel model = (DefaultTableModel) table.getModel(); model.setRowCount(0); model.setColumnCount(0); textAll.setText(""); textLog.setText(""); } -Phương thức actionRunAll() actionRunStep(): Xử lí tính tốn private void actionRunAll() { distra.getDuLieuTuFile(tfFile.getText()); distra.thuatToan_Dijkstra(choi.getSelectedIndex()); textAll.setText(distra.runAll()); } private void actionRunStep() { distra.getDuLieuTuFile(tfFile.getText()); int item = choi.getSelectedIndex(); if (choi.getSelectedItem() == "Begin" || choi1.getSelectedItem() == "End") { JOptionPane.showMessageDialog(this, "Chưa chọn điểm đầu or điểm đích!!!"); } } else { distra.thuatToan_Dijkstra(choi.getSelectedIndex()); textLog.setText(distra.runStep(choi1.getSelectedIndex())); } -Phương thức actionLoad(): Mở File Open lên private void actionLoad() { if (tfFile.getText().isEmpty() == true) { JOptionPane.showMessageDialog(this, "Chọn File !!!"); } else { distra.getDuLieuTuFile(tfFile.getText()); for (int i = 0; i < distra.getSoDinh(); i++) { choi.add(i + + ""); choi1.add(i + + ""); } loadMatrix(); } } -Phương thức loadMatrix(): Xử lí ma trận trọng số private void loadMatrix() { int a[][] = distra.getG(); int infinity = 0; int col = 1; head = new String[a.length]; data = new String[a[0].length][a.length]; for (int i = 1; i doDai[j]) { i = j; } } daXet[i] = 1; // cho i vao danh sach xet roi } for (int j = 0; j < soDinh; j++) // tinh lai dai cua cac diem chua xet { if (daXet[j] != && doDai[i] + G[i][j] < doDai[j]) { doDai[j] = doDai[i] + G[i][j]; // thay doi dai cua d[i,j] dinhTruoc[j] = i; // danh dau diem truoc j la i } } } -Phương thức runAll(): Tìm đường tất đỉnh xếp theo chi phí public String runAll() { String path = ""; for (int dinh = 0; dinh < soDinh; dinh++) { if (dinh != diemDau) { // in duong di if (doDai[dinh] < oo) { path += "Độ dài đường từ đỉnh " + ((char) (diemDau + 65)) + " đến đỉnh " + ((char) (dinh + 65)) + " là: " + doDai[dinh] + "\t "; int mang[] = new int[soDinh]; int dem = 0; int i = dinh; while (i != diemDau) { mang[dem++] = i; i = dinhTruoc[i]; } path += "\tChi tiết: " + ((char) (diemDau + 65)); for (int k = dem - 1; k >= 0; k ) { path += " >" + (char) (mang[k] + 65); } path += "\n"; } else { path += "\t\tKhơng có đường từ đỉnh " + (((char) (diemDau + 65))) + " đến đỉnh " + (((char) (dinh + 65))); } } } return path; } -Phương thức runStep(): Tìm đường điểm xếp theo chi phí public String runStep(int pointCuoi) { int diemCuoi = pointCuoi; String path = ""; // in duong di if (doDai[diemCuoi] < oo) { path += "\t\tĐộ dài đường từ đỉnh " + ((char) (diemDau + 65)) + " đến đỉnh " + ((char) (diemCuoi + 65)) + " là: " + doDai[diemCuoi] + "\t "; int mang[] = new int[soDinh]; int dem = 0; int i = diemCuoi; while (i != diemDau) { mang[dem++] = i; i = dinhTruoc[i]; } path += "\tChi tiết: " + ((char) (diemDau + 65)); for (int k = dem - 1; k >= 0; k ) { path += " >" + (char) (mang[k] + 65); } } else { path += "\t\tKhơng có đường từ đỉnh " + (((char) (diemDau + 65))) + " đến đỉnh " + (((char) (diemCuoi + 65))); } System.out.println(path); System.out.println("\n"); } return path; -Phương thức inMaTran(): in ma trận public void inMatran() { for (int i = 0; i < soDinh; i++) { System.out.print("\t\t"); for (int j = 0; j < soDinh; j++) { if (G[i][j] == 0) { System.out.print("oo\t"); } else { System.out.print(G[i][j] + "\t"); } } System.out.println(); } System.out.println(); } -Còn lại phương thức get/set giá trị thuộc tính: public int[][] getG() { return G; } public void setG(int[][] g) { G = g; } public int getSoDinh() { return soDinh; } public int getDiemDau() { return diemDau; } c Class Main: điểm xuất phát cho chương trình Kết luận Thơng qua mơn học giúp em nắm bắt tốt tốn tìm đường ngắn hai đỉnh thơng qua thuật tốn Dijkstra Ứng dụng thuật tốn vào tốn tìm đường qua nhiều điểm Áp dụng thêm kiến thức học trình học tập nhà trường để tạo ứng dụng có tác dụng thực tế