Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 13 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
13
Dung lượng
1,01 MB
Nội dung
VAI TRỊ CẤU TRÚC DỮ LIỆU TRONG CÁC BÀI TỐN ĐỒ THỊ Những tiến công nghệ phát triển lý thuyết tính tốn khoa học mang lại thay đổi chất lượng cho hệ thống lập trình Điều kéo theo thay đổi cần thiết bắt buộc việc tiếp cận tốn Tin học nói chung tốn đồ thị nói riêng Báo cáo đề cập tới tác nhân thay đổi mà học sinh cần phải quán triệt trình học tập làm việc sau này, vai trị cấu trúc liệu việc nâng cao hiệu giải thuật có việc tìm giải thuật ĐẶT VẤN ĐỀ Các toán tin học ngày nay, phạm vi chương trình phổ thơng trung học có đặc thù địi hỏi phải có cách tiếp cận việc xây dựng cài đặt giải thuật Đặc điểm phần lớn toán là: Số đỉnh n lớn, từ vài trăm ngàn đến vài triệu, Độ dàn đầy thấp: số cạnh vài vài chục phần trăm so với ma trận đầy đủ, Khơng đơn tìm độ dài đường ngắn mà phải xác định thân đường ngắn nhất, thực phân tích đánh giá khác nhóm đường có độ dài ngắn nhất, Thực truy vấn động đồ thị: Các thông số đỉnh, cạnh, điểm xuất phát, điểm đích thay đổi từ truy vấn sang truy vấn khác Các giải thuật sở kinh điển xem xét giảng dạy kỷ XX cần thiết, chưa đủ việc đào tạo bồi dưỡng học sinh khiếu tin học phù hợp với yêu cầu thực tế Một giải thuật nói chung tốn đồ thị nói riêng, muốn có hiệu phải tận dụng tối đa hợp lý khả mà môi trường kỹ thuật cung cấp, cụ thể là: Cho phép sử dụng khối lượng nhớ lớn, Khai thác cách hợp lý cấu trúc liệu mà hệ thống lập trình cung cấp, Tốc độ cao thiết bị tính tốn Thơng thường tốn cần giải cho phép sử dụng khơng 64MB Người giải toán quyền sử dụng dịch vụ thư viện chuẩn hệ thống lập trình cung cấp Việc sử dụng cấu trúc liệu này, triển khai, mang lại hiệu với toán kinh điển HÀNG ĐỢI ƯU TIÊN VÀ GIẢI THUẬT DIJSKTRA 2.1 - BÀI TOÁN Cho đồ thị n đỉnh m cạnh Đồ thị có hướng khơng Trọng số cạnh không âm Hãy xác định đường ngắn từ đỉnh s cho trước tới đỉnh lại độ dài đường 2.2 - GIẢI THUẬT Tổ chức mảng D = (d1, d2, , dn), dv lưu trữ độ dài đường ngắn từ s tới v, v = ÷ n Ban đầu ds = 0, dv = , v= ÷ n, v ≠ s Ngồi ra, cịn cần tới mảng lô gic U = (u1, u2, , un) để đánh dấu, cho biết đỉnh v xét hay chưa Ban đầu, uv = false với v= ÷ n Bản thân giải thuật Dijsktra gồm n bước Ở bước cần chọn đỉnh v có dv nhỏ số đỉnh v chưa đánh dấu, tức dv = min{di | ui = false, i = ÷ n } Cơng việc bước điều chỉnh D: xét tất cạnh (v, t) Gọi lt trọng số cạnh (v, t) Giá trị dt chỉnh lý theo công thức dt = min{dt, dv+lt} Sau n bước, tất đỉnh đánh dấu dv độ dài đường ngắn từ s đến v Nếu không tồn đường từ s đến v dv nhận giá trị Để khơi phục đường có độ dài ngắn cần tổ chức mảng P = (p1, p2, , pn), pv lưu đỉnh cuối trước đỉnh v đường ngắn từ s đến v Mỗi lần, dt thay đổi giá trị đỉnh đạt min: pt = v Tính đắn giải thuật nêu nhiều tài liệu khác điều khơng cần phải trình bày Điều quan trọng đánh giá độ phức tạp giải thuật làm để giảm độ phức tạp Giải thuật bao gồm n bước lặp, bước lặp cần duyệt tất đỉnh sau – chỉnh lý dt Như giải thuật có độ phức tạp O(n2+m) 2.3 - KỸ THUẬT CÀI ĐẶT HIỆU QUẢ CAO VỚI ĐỒ THỊ MA TRẬN THƯA Với đồ thị có số cạnh m nhỏ nhiều so với n2 độ phức tạp giải thuật giảm xuống việc cải tiến cách duyệt đỉnh bước lặp Mục tiêu đạt thông qua việc sử dụng Cấu trúc vun đống Fibonacci (Fibonacci Heap), Cấu trúc tập hợp (Set) cấu trúc Hàng đợi ưu tiên (Priority_Queue) Cấu trúc vun đống Fibonacci cho phép giải tốn tìm đường ngắn với độ phức tạp O(nlogn+m) Về mặt lý thuyết, độ phức tạp tối ưu cho chương trình giải toán dựa sở giải thuật Dijkstra Tuy nhiên việc cài đặt khác phức tạp thư viện chuẩn STL hệ thống lập trình dựa C++ chưa trực tiếp hỗ trợ Fibonacci Heap Các giải thuật dựa Set Priority_Queue không hiệu sử dụng Fibonacci heap cho độ phức tạp tốt, đủ chấp nhận – O(mlogn) Với cấu trúc tập hợp (Set), đơn vị liệu input cần tổ chức dạng cặp số nguyên (pair), phần tử thứ trọng số phần tử thứ hai đỉnh cạnh Dữ liệu tự động xếp theo trọng số tăng dần – điều mà ta cần! Việc tổ chức mảng đánh dấu U trở nên không cần thiết Khi điều chỉnh D, có thay đổi, trước hết cần xóa cặp liệu cũ, tính lại dt nạp lại cặp liệu ứng với dt vừa tính Chương trình làm việc với hàng đợi ưu tiên hoạt động nhanh chút so với phương án sử dụng tập hợp Tuy vậy, theo chất cấu trúc liệu, hệ thống khơng cung cấp dịch vụ xóa thơng tin khơng đứng đầu hàng đợi Chính phần lớn giải thuật sử dụng hàng đợi (kể hàng đợi ưu tiên) phải giải vấn đề lọc liệu thừa trình xử lý Trong giải thuật này, việc đơn so sánh giá trị lưu trữ đầu hàng đợi q với dv Khi chỉnh lý D, cặp giá trị (dt, t) nạp vào hàng đợi Cặp giá trị đứng trước cặp khác có giá trị t Cần lưu ý với khai báo priority_queue < pair > q; việc tổ chức ngầm định đặt giá trị lớn lên đầu hàng đợi Muốn có hàng đợi xếp theo thứ tự tăng dần ta cần khai báo: typedef pi2 pair; priority_queue q; Trong giải thuật nàycác giá trị khóa khơng âm, ta dùng khai báo đơn giản theo kiểu ngầm định, nạp giá trị khóa âm Kết giá trị thực nhỏ đứng đầu hàng đợi Chương trình sau giải toán nêu với liệu đưa vào từ file Dijsktra.inp theo quy cách: Dòng chứa số nguyên n m (n > 0, m ≥ 0), Nếu m > dịng m dòng chứa số nguyên a, b r cho biết có cạnh nối từ a tới b với trọng số r (1 ≤ a, b ≤ n, a ≠ b, ≤ r ≤ 106), khơng có hai giống nhau, Dòng m+2 chứa số nguyên s (1 ≤ s ≤ n), Dòng cuối chứa số nguyên k sau k số nguyên c1, c2, , ck cho biết phải dẫn xuất đường ngắn từ s tới ci, i = ÷ k, ≤ ci ≤ n Kết đưa file Dijsktra.out: Dòng chứa n số nguyên, số thứ i độ dài đường ngắn từ s đến đỉnh i Độ dài -1 không tồn đường từ s đến đỉnh đó, Dịng thứ i k dịng sau chứa thông tin đường ngắn (theo quy cách nêu ví dụ) Ví dụ: xét đồ thị 10 10 15 Các file liệu Input output: 1 3 4 2 DIJSKTRA.INP 10 5 15 10 DIJSKTRA.OUT 5 Shortets route from to 1: Shortets route from to 6: Time: sec Chương trình C++ sử dụng cấu trúc liệu Hàng đợi ưu tiên: #include #include #include #include using namespace std; const int INF = 1000000000; ifstream fi ("Dijsktra.inp"); ofstream fo ("Dijsktra.out"); pairx; int a,b,dd,k; int main() { clock_t aa=clock(); int n,m; fi>>n>>m; vector < vector < pair > > g (n+1); for(int i=1;i>a>>b>>dd;x.first=a;x.second=dd; g[b].push_back(x); x.first=b;g[a].push_back(x); } int s ; fi>>s; vector d (n+1, INF), p (n+1); d[s] = 0; priority_queue < pair > q; q.push (make_pair (0, s)); while (!q.empty()) { int v = q.top().second, cur_d = -q.top().first; q.pop(); if (cur_d > d[v]) continue; for (size_t j=0; j