Giáo trình thực hành lý thuyết đồ thị va thuật giải

Tài liệu Giáo trình thực hành lý thuyết đồ thị va thuật giải: BOÄ GIAÙO DUẽC VAỉ ẹAỉO TAẽO TRệễỉNG ẹAẽI HOẽC DAÂN LAÄP CệÛU LONG KHOA COÂNG NGHEÄ THOÂNG TIN W€X GIAÙO TRèNH THệẽC HAỉNH LYÙ THUYEÁT ẹOÀ THề VAỉ THUAÄT GIAÛI Bieõn Soaùn: ẹAỉO ANH PHA Vúnh Long, 05/2006 Giỏo Trỡnh Thực Hành Lý Thuyết Đồ Thị MỤC LỤC MỘT SỐ BÀI TOÁN...................................................................................................2 BÀI TOÁN 1.................................................................................................................2 BÀI TOÁN 2.................................................................................................................3 BÀI TOÁN 3.................................................................................................................4 BÀI TOÁN 4.................................................................................................................5 BÀI TOÁN 6.............................................................................................

pdf52 trang | Chia sẻ: Khủng Long | Lượt xem: 868 | Lượt tải: 0download
Bạn đang xem trước 20 trang mẫu tài liệu Giáo trình thực hành lý thuyết đồ thị va thuật giải, để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƯỜNG ĐẠI HỌC DÂN LẬP CỬU LONG KHOA CÔNG NGHỆ THÔNG TIN W€X GIÁO TRÌNH THỰC HÀNH LÝ THUYẾT ĐỒ THỊ VÀ THUẬT GIẢI Biên Soạn: ĐÀO ANH PHA Vĩnh Long, 05/2006 Giáo Trình Thực Hành Lý Thuyết Đồ Thị MỤC LỤC MỘT SỐ BÀI TỐN...................................................................................................2 BÀI TỐN 1.................................................................................................................2 BÀI TỐN 2.................................................................................................................3 BÀI TỐN 3.................................................................................................................4 BÀI TỐN 4.................................................................................................................5 BÀI TỐN 6.................................................................................................................7 BÀI TỐN 7.................................................................................................................8 BÀI TỐN 8.................................................................................................................9 BÀI TỐN 9...............................................................................................................10 BÀI TỐN 10.............................................................................................................11 HƯỚNG DẪN CÀI ĐẶT BÀI TỐN......................................................................12 BÀI TỐN 1...............................................................................................................12 BÀI TỐN 2...............................................................................................................17 BÀI TỐN 3...............................................................................................................20 BÀI TỐN 4...............................................................................................................22 BÀI TỐN 5...............................................................................................................25 BÀI TỐN 6...............................................................................................................32 BÀI TỐN 7...............................................................................................................35 BÀI TỐN 8...............................................................................................................38 BÀI TỐN 9...............................................................................................................43 BÀI TỐN 10.............................................................................................................48 Biên Soạn: Đào Anh Pha Trang 1 Giáo Trình Thực Hành Lý Thuyết Đồ Thị MỘT SỐ BÀI TỐN BÀI TỐN 1 Viết chương trình tìm bậc cao nhất của đỉnh trong đồ thị với đồ thị vơ hướng A[i,j] với A[i,j]=1 nếu cĩ đường đi từ i đến j và ngược lại A[i,j] = 0 nếu khơng cĩ đường đi từ i đến j. Dữ liệu vào: cho trong file Bai1.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100). - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: thơng báo kết quả ra màn hình số bậc cao nhất của đỉnh trong đồ thị đã cho. Ví dụ: Bai1.inp Kết quả: 6 Bac cao nhat: 4 0 1 1 0 0 0 1 0 0 1 1 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 1 1 0 1 0 0 0 0 1 0 Bai1.inp Kết quả: 5 Bac cao nhat: 4 0 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 1 1 1 1 0 Yêu cầu xử lý: a) Tìm đỉnh cĩ bậc cao nhất. b) Tìm bậc nhỏ nhẩt của đỉnh. c) Tìm đỉnh cĩ bậc nhỏ nhất. d) Tính tổng bậc của đồ thị. e) Đếm số đỉnh bậc chẵn và bậc lẻ. Ví dụ: Kết quả: a) Đỉnh 2,5. b) Bậc 2. c) Đỉnh 1,3,4. d) Tổng bậc của đồ thị 14. e) Số đỉnh bậc chẵn 5, số đỉnh bậc lẻ 0. Biên Soạn: Đào Anh Pha Trang 2 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 2 Viết chương trình kiểm tra tính liên thơng của một đồ thị vơ hướng A[i,j] với A[i,j]=1 nếu cĩ đường đi từ i đến j và ngược lại A[i,j] = 0 nếu khơng cĩ đường đi từ i đến j. Dữ liệu vào: cho trong file Bai2.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100). - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: thơng báo kết quả ra màn hình ”DO THI LIEN THONG” hay “ DO THI KHONG LIEN THONG”. Ví dụ: Bai2.inp Kết quả: 5 DO THI LIEN THONG 0 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 0 1 0 Bai2.inp Kết quả: 8 DO THI LIEN THONG 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 Bai2.inp Kết quả: 6 DO THI KHONG LIEN THONG 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Biên Soạn: Đào Anh Pha Trang 3 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 3 Viết chương trình đếm số thành phần liên thơng của đồ thị vơ hướng Anxn với: - A[i,j] = 1 nếu cĩ đường đi từ i đến j. - A[i,j] = 0 nếu khơng cĩ đường đi từ i đến j. - A[i,j] = A[j,i]. Dữ liệu vào: cho trong file Bai2.inp nội dung dữ liệu giống dữ liệu Bài Tốn 2. Dữ liệu ra: hiển thị số thành phần liên thơng của đồ thị ra màn hình. Ví dụ: Bai3.inp Kết quả: 6 2 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Bai3.inp Kết quả: 5 1 0 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 0 1 0 Bai3.inp Kết quả: 8 1 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 Biên Soạn: Đào Anh Pha Trang 4 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 4 Cĩ n thành phố biết rằng đường đi giữa hai các thành phố (nếu cĩ) là đường đi hai chiều. Sơ đồ mạng lưới giao thơng của n thành phố cho bởi ma trận Anxn trong đĩ: a. A[i,j] = 1 nếu cĩ đường đi từ thành phố i đến thành phố j. b. A[i,j] = 0 nếu khơng cĩ đường đi từ thành phố i đến thành phố j. c. A[i,j] = A[j,i]. Hãy xác định mọi đường từ thành phố D đến thành phố C (nếu cĩ). Dữ liệu vào: cho trong file Bai4.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: Xuất ra màn hình mọi đường đi từ đỉnh D đến C hay thơng báo khơng tồn tại đường đi từ D đến C. Ví dụ: Bai4.inp Kết quả: 5 1->2->3->4->5 1 5 1->2->4->5 0 1 0 0 1 1->5 1 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 Bai3.inp Kết quả: 5 1->2->3->4->5 1 5 1->2->5 0 1 0 1 1 1->4->3->2->5 1 0 1 0 1 1->4->5 0 1 0 1 0 1->5 1 0 1 0 1 1 1 0 1 0 Bai4.inp Kết quả: 6 KHONG CO DUONG DI TU 1 DEN 4 1 4 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Biên Soạn: Đào Anh Pha Trang 5 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 5 Một lưới giao thơng hai chiều giữa n địa điểm được cho bởi ma trận A[i,j] trong đĩ A[i,j]=1 nếu cĩ đường đi từ i đến j, cịn A[i,j] = 0 trong trường hợp ngược lại. Một người đưa thơ cần đi qua tất cả các con đường này để phát thơ, mỗi đường chỉ qua một lần. Hãy xác định một lộ trình của người đưa thơ này (cĩ thể tồn tại nhiều lộ trình khác nhau) hay thơng báo khơng tồn tại đường như vậy. Dữ liệu vào: cho trong file Bai5.inp. - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: In ra màn hình đường đi của người đưa thơ (nếu cĩ). Ví dụ: Bai5.inp Kết quả: 5 1->2->3->4->2->5->4 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 0 1 0 Bai5.inp Kết quả: 5 KHONG TON TAI DUONG DI 0 1 0 0 0 1 0 1 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 0 Bai5.inp Kết quả: 5 2->1->5->4->2->3->4 0 1 0 0 1 1 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 Biên Soạn: Đào Anh Pha Trang 6 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 6 Một người khách du lịch muốn đi thăm n thành phố được đánh số từ 1 đến n, mỗi thành phố người khách chỉ muốn đi qua chúng một lần. Mạng lưới giao thơng giữa n thành phố là hai chiều và được cho bởi ma trận A[i,j] trong đĩ A[i,j] =1 nếu cĩ đường đi giữa thành phố i và thành phố j, A[i,j] = 0 trong trường hợp ngược lại. Hãy viết chương trình thiết lập cho người khách một lộ trình (cĩ thể tồn tại nhiều lộ trình) hay thơng báo khơng tồn tại lộ trình theo yêu cầu của khách. Dữ liệu vào: cho trong file Bai6.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng 2 ghi đỉnh mà người khách du lịch xuất phát. - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: In ra màn hình đường đi của người khách (nếu cĩ). Ví dụ: Bai6.inp Kết quả: 5 1->2->3->4->5 1 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 0 1 0 Bai6.inp Kết quả: 6 KHONG TON TAI DUONG DI 1 0 1 1 0 0 0 1 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 0 Bai6.inp Kết quả: 6 KHONG TON TAI DUONG DI 1 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Biên Soạn: Đào Anh Pha Trang 7 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 7 Cĩ n thành phố biết rằng đường đi giữa các thành phố là đường đi hai chiều. Sơ đồ mạng lưới giao thơng của n thành phố cho bởi ma trận A[i,j] trong đĩ: - A[i,j] là độ dài đường đi từ thành phố i đến thành phố j. - A[i,j] = 0 nếu khơng cĩ đường đi từ thành phố i đến thành phố j. - A[i,j] = A[j,i] - A[i,j] nguyên, khơng âm. Hãy xác định đường đi ngắn nhất từ thành phố D đến thành phố C. Dữ liệu vào: đồ thị đã liên thơng và cho trong file Bai7.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: xuất ra màn hình đường đi ngắn nhất từ đỉnh D đến C và giá trị đường đi ngắn nhẩt tìm được. Ví dụ: Bai7.inp Kết quả: 6 DUONG DI NGAN NHAT LA: 5 1 6 1->2->4->6 0 1 2 0 0 0 1 0 2 2 3 0 2 2 0 5 4 0 0 2 5 0 3 2 0 3 4 3 0 4 0 0 0 2 4 0 Bai7.inp Kết quả: 6 DUONG DI NGAN NHAT LA: 8 1 6 1->2->4->6 0 1 4 0 0 0 1 0 2 6 5 0 4 2 0 7 3 0 0 6 7 0 0 1 0 5 3 0 0 3 0 0 0 1 3 0 Biên Soạn: Đào Anh Pha Trang 8 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 8 Một cơng ty cần thay tồn bộ hệ thống dây điện cho n phịng làm việc. Cho biết sơ đồ điện hiện cĩ của n căn phịng này được biều diễn bằng ma trận A[i,j] trong đĩ: - A[i,j]=A[j,i] chính là chiều dài dây điện nối liền giữa hai phịng i và j. - A[i,j] = A[j,i] = 0 nếu i khơng nối liền với j. Hãy lập trình tính độ dài cuả dây dẫn cần sử dụng sao cho cả n phịng điều cĩ điện và số lượng này là ít nhất. Dữ liệu vào: cho trong file Bai8.inp (đồ thị cho đã liên thơng). - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: lưu trong file Bai8.out với nội dung sau: - Dịng đầu lưu độ dài dây dẫn nhỏ nhất - Các dịng cịn lại lưu đường đi cần nối điện giữa đỉnh i nối với đỉnh j cĩ trọng số A[i,j] (i -> j = A[i][j]). Ví dụ: Bai8.inp Bai8.out 5 0 3 3 2 2 3 0 2 3 2 3 2 0 1 4 2 3 1 0 4 2 2 4 4 0 7 1 -> 4 = 2 4 -> 3 = 1 1 -> 5 = 2 3 -> 2 = 2 Bai8.inp Bai8.out 8 0 2 3 4 0 0 0 0 2 0 3 0 4 0 0 0 3 3 0 7 6 5 2 0 4 0 7 0 0 0 3 0 0 4 6 0 0 4 0 8 0 0 5 0 4 0 1 6 0 0 2 3 0 1 0 5 0 0 0 0 8 6 5 0 20 1 -> 2 = 2 1 -> 3 = 3 3 -> 7 = 2 7 -> 6 = 1 7 -> 4 = 3 2 -> 5 = 4 7 -> 8 = 5 Biên Soạn: Đào Anh Pha Trang 9 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 9 Cĩ n thành phố được đánh số từ 1 đến n. Mạng lưới giao thơng giữa các thành phố là đường hai chiều. Trên đường đi từ thành phố i đến thành phố j, người ta khơng được mang quá A[i,j] đơn vị hàng. Nếu khơng cĩ đường đi từ thành phố i đến thành phố j thì xem như A[i,j] = 0. Cần vận chuyển hàng từ thành phố D đến thành phố C. Hãy thiết lập kế hoạch vận chuyển sao cho khối lượng hàng vận chuyển là nhiều nhất. Dữ liệu vào: đồ thị đã liên thơng và cho trong file Bai9.inp với nội dung - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: xuất ra màn hình kế hoạch vận chuyển từ đỉnh D đến C và giá trị đường đi ngắn nhẩt tìm được. Ví dụ: Bai9.inp Kết quả: 6 KHOI LUONG VAN CHUYEN NHIEU NHAT LA: 2 1 6 1->3->4->6 0 1 2 0 0 0 1 0 2 2 3 0 2 2 0 5 4 0 0 2 5 0 3 2 0 3 4 3 0 4 0 0 0 2 4 0 Bai9.inp Kết quả: 6 KHOI LUONG VAN CHUYEN NHIEU NHAT LA: 3 1 6 1->3->4->2->5->6 0 1 4 0 0 0 1 0 2 6 5 0 4 2 0 7 3 0 0 6 7 0 0 1 0 5 3 0 0 3 0 0 0 1 3 0 Biên Soạn: Đào Anh Pha Trang 10 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 10 Cĩ n thành phố biết rằng đường đi giữa các thành phố là đường đi hai chiều. Sơ đồ mạng lưới giao thơng của n thành phố cho bởi ma trận A[i,j] trong đĩ: - A[i,j] là độ dài đường đi từ thành phố i đến thành phố j. - A[i,j] = 0 nếu khơng cĩ đường đi từ thành phố i đến thành phố j. - A[i,j] = A[j,i]. - A[i,j] nguyên, khơng âm. Hãy xác định đường đi dài nhất từ thành phố D đến thành phố C với điều kiện thành phố đã qua khơng được đi lại. Dữ liệu vào: đồ thị đã liên thơng và cho trong file Bai10.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: xuất ra màn hình đường đi dài nhất từ đỉnh D đến C và giá trị đường đi ngắn nhẩt tìm được. Ví dụ: Bai10.inp Kết quả: 6 DUONG DI DAI NHAT LA: 16 1 6 1->2->4->3->5->6 0 1 2 0 0 0 1 0 2 2 3 0 2 2 0 5 4 0 0 2 5 0 3 2 0 3 4 3 0 4 0 0 0 2 4 0 Bai10.inp Kết quả: 6 DUONG DI DAI NHAT LA: 25 1 6 1->3->4->2->5->6 0 1 4 0 0 0 1 0 2 6 5 0 4 2 0 7 3 0 0 6 7 0 0 1 0 5 3 0 0 3 0 0 0 1 3 0 Biên Soạn: Đào Anh Pha Trang 11 Giáo Trình Thực Hành Lý Thuyết Đồ Thị HƯỚNG DẪN CÀI ĐẶT BÀI TỐN BÀI TỐN 1 Viết chương trình tìm bậc cao nhất của đỉnh trong đồ thị với đồ thị vơ hướng A[i,j] với A[i,j]=1 nếu cĩ đường đi từ i đến j và ngược lại A[i,j] = 0 nếu khơng cĩ đường đi từ i đến j. Dữ liệu vào: cho trong file Bai1.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100). - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: thơng báo kết quả ra màn hình số bậc cao nhất của đỉnh trong đồ thị đã cho. Ví dụ: Bai1.inp Kết quả: 6 Bac cao nhat: 4 0 1 1 0 0 0 1 0 0 1 1 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 1 1 0 1 0 0 0 0 1 0 Bai1.inp Kết quả: 5 Bac cao nhat: 4 0 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 1 1 1 1 0 Yêu cầu xử lý: f) Tìm đỉnh cĩ bậc cao nhất. g) Tìm bậc nhỏ nhẩt của đỉnh. h) Tìm đỉnh cĩ bậc nhỏ nhất. i) Tính tổng bậc của đồ thị. j) Đếm số đỉnh bậc chẵn và bậc lẻ. Ví dụ: Kết quả: f) Đỉnh 2,5. g) Bậc 2. h) Đỉnh 1,3,4. i) Tổng bậc của đồ thị 14. Số đỉnh bậc chẵn 5, số đỉnh bậc lẻ 0. Biên Soạn: Đào Anh Pha Trang 12 Giáo Trình Thực Hành Lý Thuyết Đồ Thị HƯỚNG DẪN CÀI ĐẶT Tổng số phần tử khác khơng trên dịng i của ma trận liên kết của đồ thị chính là số bậc của đỉnh i (i=1..n). 9 Bậc lớn nhất của đỉnh: Tính bậc từng đỉnh của đồ thị, so sánh tìm ra bậc lớn nhất. 9 Đỉnh cĩ bậc lớn nhất: Tính bậc từng đỉnh của đồ thị, so sánh với bậc lớn nhất của đồ thị nếu bằng thì xuất đỉnh cĩ bậc lớn nhất ra màn hình. 9 Bậc nhỏ nhất của đỉnh: Tính bậc từng đỉnh của đồ thị, so sánh tìm ra bậc nhỏ nhất. 9 Đỉnh cĩ bậc nhỏ nhất: Tính bậc từng đỉnh của đồ thị, so sánh với bậc nhỏ nhất của đồ thị nếu bằng thì xuất đỉnh cĩ bậc nhỏ nhất ra màn hình. 9 Tìm đỉnh bậc lẻ và số đỉnh bậc lẻ: Tính bậc từng đỉnh của đồ thị, kiểm tra đỉnh tương ứng cĩ phải là bậc lẻ hay khơng nếu phải xuất ra màn hình và tăng số đỉnh bậc lẻ lên 1. 9 Tìm đỉnh bậc chẵn và số đỉnh bậc chẵn: tương tự như tìm số đỉnh bậc lẻ. 9 Tổng bậc của đồ thị: Tổng tất cả các phần tử khác khơng của ma trận liên kết chính là tổng số bậc của đồ thị. CHƯƠNG TRÌNH MẪU #include #include #include #include #define TenFile "Bai1.inp" /*Dọc file dữ liệu bài tốn*/ void Doc_File(int **A,int &n) { FILE*f = fopen(TenFile,"rb"); fscanf(f,"%d",&n); *A = new int [n]; cout<<"Ma Tran Lien Ket Cua Do Thi"; for(int i =0;i<n;i++) { A[i] = new int [n]; cout<<endl; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<" "<<A[i][j]; } } fclose(f); } /*Bậc lớn nhất của đỉnh*/ int BacLonNhat(int**A,int n) { int max = 0,Bac; Biên Soạn: Đào Anh Pha Trang 13 Giáo Trình Thực Hành Lý Thuyết Đồ Thị for(int i = 0; i<n; i++) { Bac = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) Bac++; if(Bac > max) max = Bac; } return max; } /*Bậc nhỏ nhất của đỉnh*/ int BacNhoNhat(int**A,int n){ int min = MAXINT,Bac; for(int i = 0; i<n; i++) { Bac = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) Bac++; if(Bac < min) min = Bac; } return min; } /*Tổng bậc của đồ thị*/ int TongBac(int**A,int n){ int Tong = 0; for(int i = 0; i<n; i++) for(int j = 0; j<n; j++) if(A[i][j]>0) Tong++; return Tong; } /*Các đỉnh cĩ bậc nhỏ nhất*/ void DinhBacNhoNhat(int**A, int n){ int min = BacNhoNhat(A,n), Bac; for(int i = 0; i<n; i++) { Bac = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) Bac++; if(Bac == min) cout<<" "<<i+1; Biên Soạn: Đào Anh Pha Trang 14 Giáo Trình Thực Hành Lý Thuyết Đồ Thị } } /*Các đỉnh cĩ bậc lớn nhất*/ void DinhBacLonNhat(int**A, int n){ int max = BacLonNhat(A,n), Bac; for(int i = 0; i<n; i++) { Bac = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) Bac++; if(Bac == max) cout<<" "<<i+1; } } /*Các đỉnh bậc chẵn và số đỉnh bậc chẵn*/ void DinhBacChan(int**A, int n) { int Bac,Tong=0; for(int i = 0; i<n; i++) { Bac = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) Bac++; if(Bac%2==0) { cout<<" "<<i+1; Tong++; } } cout<<"\n\t So Dinh Bac Chan: "<<Tong; } /*Các đỉnh bậc lẻ và số đỉnh bậc lẻ*/ void DinhBacLe(int**A, int n){ int Bac,Tong=0; for(int i = 0; i<n; i++) { Bac = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) Bac++; if(Bac%2==1) { cout<<" "<<i+1; Tong++; } } Biên Soạn: Đào Anh Pha Trang 15 Giáo Trình Thực Hành Lý Thuyết Đồ Thị cout<<"\n\t So Dinh Bac Le: "<<Tong; } /*Chuong Trinh Chinh*/ void main() { clrscr(); int **A,n; Doc_File(A,n); cout<<"\n1. Bac Lon Nhat Cua Dinh: "<<BacLonNhat(A,n); cout<<"\n2. Dinh Co Bac Lon Nhat:"; DinhBacLonNhat(A,n); cout<<"\n3. Bac Nho Nhat Cua Dinh: "<<BacNhoNhat(A,n); cout<<"\n4. Dinh Co Bac Nho Nhat:"; DinhBacNhoNhat(A,n); cout<<"\n5. Dinh Co Bac Chan:"; DinhBacChan(A,n); cout<<"\n6. Dinh Co Bac Le:"; DinhBacLe(A,n); cout<<"\n7. Tong Bac Cua Do Thi: "<<TongBac(A,n); delete*A; getch(); } Biên Soạn: Đào Anh Pha Trang 16 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 2 Viết chương trình kiểm tra tính liên thơng của một đồ thị vơ hướng A[i,j] với A[i,j]=1 nếu cĩ đường đi từ i đến j và ngược lại A[i,j] = 0 nếu khơng cĩ đường đi từ i đến j. Dữ liệu vào: cho trong file Bai2.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100). - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: thơng báo kết quả ra màn hình ”DO THI LIEN THONG” hay “ DO THI KHONG LIEN THONG”. Ví dụ: Bai2.inp Kết quả: 5 DO THI LIEN THONG 0 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 0 1 0 Bai2.inp Kết quả: 8 DO THI LIEN THONG 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 Bai2.inp Kết quả: 6 DO THI KHONG LIEN THONG 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Biên Soạn: Đào Anh Pha Trang 17 Giáo Trình Thực Hành Lý Thuyết Đồ Thị HƯỚNG DẪN THUẬT TỐN Ý tưởng: Sử dụng thuật tốn loang . Bước 1: Xuất phát từ một đỉnh bất kỳ của đồ thị. Ta đánh dấu đỉnh xuất phát và chuyển sang bước 2. Bước 2: Từ một đỉnh i đã đánh dấu, ta đánh dấu đỉnh j nếu A[i,j] = 1 và j chưa được đánh dấu và chuyển sang bước 3. Bước 3: Thực hiện bước 2 cho đến khi khơng cịn thực hiện được nữa chuyển sang bước 4. Bước 4: Kiểm tra nếu số đỉnh đánh dấu nhỏ hơn n (hay tồn tại ít nhất một đỉnh chưa được đánh dấu) đồ thị sẽ khơng liên thơng và ngược lại đồ thị liên thơng. HƯỚNG DẪN CÀI ĐẶT Tổ chức cấu trúc dữ liệu để lưu trữ sự đánh dấu các đỉnh của đồ thị. ¾ Ta tổ chức một mảng 1 chiều (char*DanhDau) để lưu trữ những đỉnh của đồ thị cĩ được đánh dấu hay khơng. Chỉ số của mảng chính là chỉ số đỉnh của đồ thị. ¾ DanhDau[i]=0 nếu đỉnh i chưa được đánh dấu và DanhDau[i]=1 nếu đỉnh i đã được đánh dấu. Ví dụ: DanhDau[5]=1, DanhDau[3]=0 cĩ nghĩa là đỉnh thứ 5 của đồ thị đã được dánh đấu và đỉnh thứ 3 của đồ thị chưa được dánh dấu. ¾ Trong thuật tốn, trước tiên ta khởi tạo tất cả các đỉnh của đồ thị là chưa được đánh dấu. Nghĩa là DanhDau[i]=0, i=0..n-1. o Dánh dấu đỉnh dầu tiên của đồ thị (DanhDau[0]=1). o Từ đỉnh i đã đánh dấu (DanhDau[i]=1), ta đánh dấu đỉnh j (DanhDau[j]=1) nếu A[i][j] = 1 và j chưa được đánh dấu (DanhDau[j]=0). Cứ tiếp tục như vậy cho đến khi khơng thực hiện được nữa. o Nếu đỉnh nào chưa đánh dấu (tồn tại DanhDau[k]=0, 0≤k<n) thì đồ thị khơng liên thơng và ngược lại. CHƯƠNG TRÌNH MẪU #include #include #include #define TenFile "Bai2.inp" /*Dọc file dữ liệu*/ void Doc_File(int **A,int &n){ FILE*f = fopen(TenFile,"rb"); fscanf(f,"%d",&n); *A = new int [n]; cout<<"Ma Tran Lien Ket Cua Do Thi"; for(int i =0;i<n;i++) { A[i] = new int [n]; cout<<endl; Biên Soạn: Đào Anh Pha Trang 18 Giáo Trình Thực Hành Lý Thuyết Đồ Thị for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<" "<<A[i][j]; } } fclose(f); } /*Kiểm tra liên thơng: Nếu liên thơng trả về giá trị 1, ngược lại trả về giá trị 0*/ char Lien_Thong(int **A,int n) { char*DanhDau = new char [n]; char ThanhCong; int Dem=0; for(int i = 0; i<n; i++) DanhDau[i] = 0; DanhDau[0] = 1; Dem++; do { ThanhCong =1; for(i = 0; i<n; i++) if(DanhDau[i]==1) { for(int j = 0; j<n; j++) if (DanhDau[j] == 0 && A[i][j] > 0) { DanhDau[j] = 1; ThanhCong =0; Dem++; if(Dem == n) return 1; } } }while (ThanhCong == 0); return 0; } /*Chương trình chính*/ void main() { clrscr(); int **A,n; Doc_File(A,n); if (Lien_Thong(A,n)==1) cout<<"\nDO THI LIEN THONG"; else cout<<"\nDO THI KHONG LIEN THONG"; delete *A; getch(); } Biên Soạn: Đào Anh Pha Trang 19 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 3 Viết chương trình đếm số thành phần liên thơng của đồ thị vơ hướng Anxn với: - A[i,j] = 1 nếu cĩ đường đi từ i đến j. - A[i,j] = 0 nếu khơng cĩ đường đi từ i đến j. - A[i,j] = A[j,i]. Dữ liệu vào: cho trong file Bai2.inp nội dung dữ liệu giống dữ liệu Bài Tập2. Dữ liệu ra: hiển thị số thành phần liên thơng của đồ thị ra màn hình. Ví dụ: Bai3.inp Kết quả: 6 2 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Bai3.inp Kết quả: 5 1 0 0 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 0 1 0 Bai3.inp Kết quả: 8 1 0 1 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 HƯỚNG DẪN THUẬT TỐN Ý tưởng: Sử dụng thuật tốn loang giống như bài tốn 1. Bước 0: Khởi tạo số thành phần liên thơng bằng 0. Bước 1: Xuất phát từ một đỉnh chưa được đánh dấu của đồ thị. Ta đánh dấu đỉnh xuất phát, tăng số thành phần liên thơng lên 1 và chuyển sang bước 2. Bước 2: Từ một đỉnh i đã đánh dấu, ta đánh dấu đỉnh j nếu A[i,j] = 1 và j chưa được đánh dấu và chuyển sang bước 3. Biên Soạn: Đào Anh Pha Trang 20 Giáo Trình Thực Hành Lý Thuyết Đồ Thị Bước 3: Thực hiện bước 2 cho đến khi khơng cịn thực hiện được nữa chuyển sang bước 4. Bước 4: Nếu số số đỉnh đánh dấu bằng n (mọi đỉnh đều được đánh dấu) kết thúc thuật tốn, ngược lại quay về bước 1. Chú ý: Nếu số thành phần liên thơng bằng 1 đồ thị liên thơng. HƯỚNG DẪN CÀI ĐẶT Cài đặt tương tự như bài tốn 2. CHƯƠNG TRÌNH MẪU /*Hàm trả về số thành phần liên thơng của đồ thị vơ hướng */ int TPLien_Thong(int **A, int n) { char*DanhDau = new char [n]; char ThanhCong; int Dem=0, i,j, MLT=0; for( i = 0; i<n; i++) DanhDau[i] = 0; do { j = 0; while(DanhDau[j]==1) j++; DanhDau[j] = 1; Dem++; MLT++; do { ThanhCong =0; for(i = 0; i<n; i++) if(DanhDau[i]==1) for(j = 0; j<n; j++) if (DanhDau[j] == 0 && A[i][j] > 0) { DanhDau[j] = 1; ThanhCong =1; Dem++; if(Dem == n) return MLT; } }while (ThanhCong == 1); } while(Dem<n); return MLT; } Biên Soạn: Đào Anh Pha Trang 21 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 4 Cĩ n thành phố biết rằng đường đi giữa hai các thành phố (nếu cĩ) là đường đi hai chiều. Sơ đồ mạng lưới giao thơng của n thành phố cho bởi ma trận Anxn trong đĩ: d. A[i,j] = 1 nếu cĩ đường đi từ thành phố i đến thành phố j. e. A[i,j] = 0 nếu khơng cĩ đường đi từ thành phố i đến thành phố j. f. A[i,j] = A[j,i]. Hãy xác định mọi đường từ thành phố D đến thành phố C (nếu cĩ). Dữ liệu vào: đồ thị liên thơng và cho trong file Bai4.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: Xuất ra màn hình mọi đường đi từ đỉnh D đến C hay thơng báo khơng tồn tại đường đi từ D đến C. Ví dụ: Bai4.inp Kết quả: 5 1->2->3->4->5 1 5 1->2->4->5 0 1 0 0 1 1->5 1 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 Bai3.inp Kết quả: 5 1->2->3->4->5 1 5 1->2->5 0 1 0 1 1 1->4->3->2->5 1 0 1 0 1 1->4->5 0 1 0 1 0 1->5 1 0 1 0 1 1 1 0 1 0 Bai4.inp Kết quả: 6 KHONG CO DUONG DI TU 1 DEN 4 1 4 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 Biên Soạn: Đào Anh Pha Trang 22 Giáo Trình Thực Hành Lý Thuyết Đồ Thị HƯỚNG DẪN THUẬT TỐN Sử dụng kỹ thuật tìm kiếm theo chiều sâu. HƯỚNG DẪN CÀI ĐẶT Sử dụng kỹ thuật cài đặt tìm kiếm theo phương pháp đệ quy. CHƯƠNG TRÌNH MẪU #include #include #include #define FileIn "Bai4.inp" int Dem = 0; //Dếm số đường đi int*L; //Lưu lại đường đã đi char*DanhDau; //Đánh dấu đỉnh đã đi int **A,n,D,C; /*Dọc file dữ liệu theo yêu cầu của chương trình*/ void Doc_File(){ FILE*f = fopen(FileIn,"rb"); fscanf(f,"%d%d%d",&n,&D,&C); cout<<"Ma Tran Lien Ket Tuong Ung.\n"; cout<<D<<" "<<C<<endl; *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<A[i][j]<<" "; } cout<<endl; } fclose(f); D--; C--; } /*Khởi tạo các tham số ban đầu cho chương trình*/ void KhoiTao() { DanhDau = new char [n]; L = new int [n]; for (int i = 0; i<n; i++) { //Tất cả các đỉnh chưa được đánh dấu DanhDau[i] = 0; L[i] = 0; } Biên Soạn: Đào Anh Pha Trang 23 Giáo Trình Thực Hành Lý Thuyết Đồ Thị DanhDau[D] = 1; //Đánh dấu đỉnh đầu tiên L[0] = D; //Lưu lại đỉnh đầu tiên là đỉnh xuất phát } void InDuongDi(int SoCanh) { Dem++; cout<<endl<<D+1; for (int i = 1; i<SoCanh; i++) cout "<<L[i]+1; } /*Thủ tục đệ quy tìm kiếm đường đi*/ void TimKiem(int SoCanh) { if(L[SoCanh-1] == C) InDuongDi(SoCanh); else { for(int i = 0; i<n; i++) if( A[L[SoCanh-1]][i]>0 && DanhDau[i] == 0){ L[SoCanh] = i; DanhDau[i] = 1; TimKiem(SoCanh+1); //Tìm kiếm đỉnh tiếp theo L[SoCanh] = 0; DanhDau[i] = 0; } } } /*Chương trình chính*/ void main() { clrscr(); Doc_File(); KhoiTao(); cout<<"Duong di tu "<<D+1<<" den "<<C+1; TimKiem(1); if(Dem==0) cout<<" khong co"; delete*A,DanhDau,L; getch(); } Biên Soạn: Đào Anh Pha Trang 24 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 5 Một lưới giao thơng hai chiều giữa n địa điểm được cho bởi ma trận A[i,j] trong đĩ A[i,j]=1 nếu cĩ đường đi từ i đến j, cịn A[i,j] = 0 trong trường hợp ngược lại. Một người đưa thơ cần đi qua tất cả các con đường này để phát thơ, mỗi đường chỉ qua một lần. Hãy xác định một lộ trình của người đưa thơ này (cĩ thể tồn tại nhiều lộ trình khác nhau) hay thơng báo khơng tồn tại đường như vậy. Dữ liệu vào: cho trong file Bai5.inp. - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: In ra màn hình đường đi của người đưa thơ (nếu cĩ). Ví dụ: Bai5.inp Kết quả: 5 1->2->3->4->2->5->4 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 0 1 0 Bai5.inp Kết quả: 5 KHONG TON TAI DUONG DI 0 1 0 0 0 1 0 1 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 0 Bai5.inp Kết quả: 5 2->1->5->4->2->3->4 0 1 0 0 1 1 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 HƯỚNG DẪN THUẬT TỐN Bài tốn 5 chính là bài tốn tìm đường đi Euler. Điều kiện để cĩ đường đi Euler là: - Đồ thị liên thơng. - Đồ thị cĩ khơng quá 2 đỉnh bậc lẻ. Nếu cĩ 2 đỉnh bậc lẻ thì đỉnh xuất phát tìm đường đi phải là đỉnh bậc lẻ. Biên Soạn: Đào Anh Pha Trang 25 Giáo Trình Thực Hành Lý Thuyết Đồ Thị Ý tưởng thuật tốn: Sử dụng kỹ thuật xố cạnh. Nghĩa là, khi ta đi qua bất kỳ cạnh nào ta phải xố cạnh tương ứng bằng cách gán trọng số đường đi của cạnh mới đi qua bằng 0. Thuật tốn kết thúc khi ta đi qua tất cả các cạnh của đồ thị khi đĩ ma trận trận liên kết của đồ thị bằng 0. HƯỚNG DẪN CÀI ĐẶT ¾ Cài đặt hàm kiểm tra tính liên thơng của đồ thị nếu liên thơng trả về kết quả 1 ngược lại trả về kết quả 0. ¾ Cài đặt hàm kiểm tra đồ thị cĩ thỏa mãn tồn tại khơng quá 2 đỉnh bậc lẻ nếu thỏa mãn trả về kết quả 1 ngược lại trả về kết quả 0. Nếu tồn tại đỉnh bậc lẻ thì đỉnh bậc lẻ chính là đỉnh xuất phát và trong quá trình kiểm tra chúng ta đếm luơn số cạnh của đồ thị. Bởi vì thuật tốn kết thúc khi ta đi hết tất cả mọi cảnh của đồ thị. ¾ Cài đặt thuật tốn tìm đường đi Euler: trước tiên kiểm tra xem đồ thị co thỏa mãn điều kiện tồn tại đường đi Euler hay chưa nếu khơng thỏa mãn thì thuật tốn kết thúc. Ngược lại ta tìm đường đi Euler như sau: - Chọn đỉnh xuất phát: nếu tồn tại đỉnh bậc lẻ thì chọn đỉnh bậc lẻ làm đỉnh xuất phát, nếu khơng tồn tại đỉnh bậc lẻ thì chọn 1 đỉnh bất kỳ thơng thường ta chọn đỉnh 1 làm đỉnh xuất phát. - Từ đỉnh xuất phát ta đi tới đỉnh kề nĩ và xĩa cạnh tương ứng. Nếu j là đỉnh kề với đỉnh xuất phát thì A[xuất phát][j]= A[j][xuất phát] = 0 và đỉnh xuất phát ta gán bằng đỉnh j. Lặp lại cho đến khi khơng cịn đi được nữa (đi qua mọi cạnh của đồ thị) thì thuật tốn kết thúc. CHƯƠNG TRÌNH MẪU #include #include #include #include #define TenFile "Bai5.inp" /*Dọc dữ liệu của bài tốn*/ void Doc_File(int **A,int &n) { FILE*f = fopen(TenFile,"rb"); fscanf(f,"%d",&n); *A = new int [n]; cout<<"Ma Tran Lien Ket Cua Do Thi"; for(int i =0;i<n;i++) { A[i] = new int [n]; cout<<endl; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); Biên Soạn: Đào Anh Pha Trang 26 Giáo Trình Thực Hành Lý Thuyết Đồ Thị cout<<" "<<A[i][j]; } } fclose(f); } /*Kiểm tra tính liên thơng của đồ thị. Đồ thị liên thơng thì hàm trả về giá trị 1, ngược lại hàm trả về giá trị 0.*/ char LienThong(int **A,int n) { char*DanhDau = new char [n]; char ThanhCong; int Dem=0; for(int i = 0; i<n; i++) DanhDau[i] = 0; DanhDau[0] = 1; Dem++; do { ThanhCong =1; for(i = 0; i<n; i++) if(DanhDau[i]==1) { for(int j = 0; j<n; j++) if (DanhDau[j] == 0 && A[i][j] > 0) { DanhDau[j] = 1; ThanhCong =0; Dem++; if(Dem == n) return 1; } } }while (ThanhCong == 0); return 0; } /*Kiểm tra đồ thị cĩ quá 2 đỉnh bậc lẻ hay khơng. Nếu quá 2 đỉnh bậc lẻ hàm trả về giá trị 0, ngược lại hàm trả về giá trị 1. Tìm đỉnh xuất phát lưu trong biến XP và tổng số cạnh lưu trong biến Canh*/ char KiemTraBacLe(int**A, int n,int &XP, int &Canh) { int BacDinh,BacLe=0; Canh = 0; XP = 0; for(int i = n-1; i>=0; i--) { BacDinh = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) BacDinh++; Biên Soạn: Đào Anh Pha Trang 27 Giáo Trình Thực Hành Lý Thuyết Đồ Thị if(BacDinh%2==1) { XP= i; BacLe++; } Canh+=BacDinh; } Canh = Canh/2; if(BacLe>2) return 0; else return 1; } /*Tim mot duong di Euler*/ void Euler(int**A,int n){ int XuatPhat,SoCanh,Dem; int *LuuDuong; if(LienThong(A,n)==1 && KiemTraBacLe(A,n,XuatPhat,SoCanh)==1){ LuuDuong = new int[SoCanh+1]; LuuDuong[0] = XuatPhat; Dem = 1; do{ int j = 0; while(A[XuatPhat][j]==0) j++; A[XuatPhat][j] = A[j][XuatPhat] = 0; LuuDuong[Dem] = XuatPhat = j; Dem++; }while(Dem<=SoCanh); cout<<"\nDuong Di Cua Nguoi Dua Tho:\n"<<LuuDuong[0]+1; for(int i = 1; i<=SoCanh; i++) cout "<<LuuDuong[i]+1; }else cout<<"\nKhong ton tai duong di."; } /*Chương trình chính*/ void main() { clrscr(); int **A,n; Doc_File(A,n); Euler(A,n); delete*A; getch(); } Biên Soạn: Đào Anh Pha Trang 28 Giáo Trình Thực Hành Lý Thuyết Đồ Thị CẢI TIẾN THUẬT TỐN XỬ LÝ CÁC TRƯỜNG HỢP ĐẶC BIỆT 1. Trường hợp đồ thị cĩ 2 đỉnh bậc lẻ trong đĩ cĩ 1đỉnh bậc 1. Xét đồ thị: Nếu chúng ta xuất phát từ đỉnh 4. Khi chúng ta đi 4->2->1 đồ thị của ta sẽ tương ứng với thuật tốn xố cạnh là: Khi đĩ điểm xuất phát của ta sẽ bắt đầu từ đỉnh 1, tại đỉnh này chúng ta sẽ khơng cịn đường đi nữa vì nĩ là đỉnh cơ lập. Để khắc phục được hiện trạng này chúng ta phải chọn ưu tiên đỉnh xuất phát là đỉnh cĩ bậc 1 và đỉnh kết thúc sẽ là đỉnh bậc lẻ cịn lại. Bai5.inp Kết quả: 6 4->2->5->1->3->5->6->2 0 0 1 0 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0 0 1 0 1 0 0 1 0 Hàm cải tiến kiểm tra đỉnh bậc lẻ và chon đỉnh xuất phát. char KiemTraBacLe(int**A, int n,int &XP, int &Canh) { int BacDinh,BacLe=0,T=0; Canh = XP = 0; for(int i = 0; i<n; i++) { BacDinh = 0; for(int j = 0; j<n; j++) if(A[i][j]>0) BacDinh++; if(BacDinh%2==1) { if(BacDinh==1) { T = 1; XP= i; } Biên Soạn: Đào Anh Pha Trang 29 Giáo Trình Thực Hành Lý Thuyết Đồ Thị if(T = 0) XP = i; BacLe++; } Canh+=BacDinh; } Canh = Canh/2; if(BacLe>2) return 0; else return 1; } 2. Trường hợp đồ thị cĩ 2 đỉnh bậc lẻ trong đĩ cĩ 2 đỉnh bậc 1. Xử lý tương tự như trường hợp 1 nhưng ta phải lưu vết đường đi đã đi qua để tránh trường hợp đường đi sau khi xĩa thì đỉnh tương ứng xuất phát là đỉnh cơ lập. Cĩ nhiều cách để lưu vết, tìm kiếm bằng phương pháp đệ quy là một trong những cánh lưu vết hiệu quả và đơn giản. Tuy nhiên đồ phức tạp của thuật tốn quá lớn nên trong thực tế người ta ích sử dụng phương pháp này. 3. Kỹ thuật tìm kiếm đệ quy tìm đường đi Euler. #include #include #include #define Filename "Bai5.inp" /*Khai báo các biến tồn cục*/ int Dem = 0; //Đếm số đường đi int*L; //Lưu lại đỉnh đã đi int **A,n int XuatPhat=0; //Đỉnh xuẩt phát tìm kiếm là đỉnh bậc lẻ nếu đồ thị cĩ đỉnh bậc lẻ int SoCanh=0; //Lưu số cạnh của đồ thị vì đường đi đi qua tất cả các cạnh /*Dọc file dữ liệu và khởi tạo ban đầu*/ void Doc_File(){ int BacDinh; FILE*f = fopen(Filename,"rb"); fscanf(f,"%d",&n); cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<n<<endl; *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; BacDinh = 0; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<A[i][j]<<" "; Biên Soạn: Đào Anh Pha Trang 30 Giáo Trình Thực Hành Lý Thuyết Đồ Thị if(A[i][j] == 1) BacDinh++; } if(BacDinh%2==1) XuatPhat = i; //Xuẩt phát là đỉnh bậc lẻ SoCanh+=BacDinh; cout<<endl; } fclose(f); SoCanh = SoCanh/2; //Số cạnh = tổng bậc /2 L = new int [SoCanh+1]; //Khởi tạo lưu đỉnh L[0] = XuatPhat; } /*Xuất đường đi tìm được ra màn hình*/ void InDuongDi() { Dem++; cout<<endl<<XuatPhat+1; for (int i = 1; i<=SoCanh; i++) cout "<<L[i]+1; } /*Thủ tục tìm kiếm đệ quy*/ void TimKiem(int Canh) { /*Tìm cho đến khi cạnh tìm được lớn hơn số cạnh của đồ thị mới xuất đường đi*/ if(Canh > SoCanh && Dem ==0 ) InDuongDi(); else { for(int i = 0; i<n; i++) if( A[L[Canh-1]][i]>0 && Dem==0){ L[Canh] = i; A[L[Canh-1]][i]=A[i][L[Canh-1]]=0; //Xĩa cạnh TimKiem(Canh+1); //Tìm đỉnh tiếp theo A[L[Canh-1]][i]=A[i][L[Canh-1]]=1; //Phục hồi cạnh L[Canh] = 0; } } } void main() { Doc_File(); cout<<"\nDUONG DI"; TimKiem(1); if(Dem==0) cout<<" KHONG CO"; delete*A,L; getch(); } Biên Soạn: Đào Anh Pha Trang 31 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 6 Một người khách du lịch muốn đi thăm n thành phố được đánh số từ 1 đến n, mỗi thành phố người khách chỉ muốn đi qua chúng một lần. Mạng lưới giao thơng giữa n thành phố là hai chiều và được cho bởi ma trận A[i,j] trong đĩ A[i,j] =1 nếu cĩ đường đi giữa thành phố i và thành phố j, A[i,j] = 0 trong trường hợp ngược lại. Hãy viết chương trình thiết lập cho người khách một lộ trình (cĩ thể tồn tại nhiều lộ trình) hay thơng báo khơng tồn tại lộ trình theo yêu cầu của khách. Dữ liệu vào: cho trong file Bai6.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng 2 ghi đỉnh mà người khách du lịch xuất phát. - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: In ra màn hình đường đi của người khách (nếu cĩ). Ví dụ: Bai6.inp Kết quả: 5 1->2->3->4->5 1 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 0 1 0 Bai6.inp Kết quả: 6 KHONG TON TAI DUONG DI 1 0 1 1 0 0 0 1 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 0 Bai6.inp Kết quả: 5 2->1->5->4->3 2 0 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1 0 Biên Soạn: Đào Anh Pha Trang 32 Giáo Trình Thực Hành Lý Thuyết Đồ Thị Bai6.inp Kết quả: 6 KHONG TON TAI DUONG DI 1 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 0 HƯỚNG DẪN THUẬT TỐN Sử dụng kỹ thuật tìm kiếm theo chiều sâu. HƯỚNG DẪN CÀI ĐẶT Sử dụng kỹ thuật cài đặt tìm kiếm theo phương pháp đệ quy. CHƯƠNG TRÌNH MẪU #include #include #include #define FileIn "Bai6.inp" int Dem = 0; //Dếm số đường đi int*L; //Lưu lại đường đi char*DanhDau; //Dánh dấu đỉnh đã đi int **A,n,D; /*Dọc file dữ liệu bài tốn*/ void Doc_File() { FILE*f = fopen(FileIn,"rb"); fscanf(f,"%d%d",&n,&D); cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<D<<endl; *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<A[i][j]<<" "; } cout<<endl; } fclose(f); D--; } /*Khởi tạo dữ liệu ban đầu cho bài tốn*/ void KhoiTao() { Biên Soạn: Đào Anh Pha Trang 33 Giáo Trình Thực Hành Lý Thuyết Đồ Thị DanhDau = new char [n]; L = new int [n]; for (int i = 0; i<n; i++) { DanhDau[i] = 0; L[i] = 0; } DanhDau[D] = 1; L[0] = D; } /*In đường đi của bài tốn ra màn hình*/ void InDuongDi(int Dinh) { Dem++; cout<<endl<<D+1; for (int i = 1; i<Dinh; i++) cout "<<L[i]+1; } /*Tìm kiếm đường đi*/ void TimKiem(int Dinh) { if(Dinh == n && Dem == 0) InDuongDi(Dinh); else { for(int i = 0; i<n; i++) if( A[L[Dinh-1]][i]>0 && DanhDau[i] == 0 && Dem==0){ L[Dinh] = i; DanhDau[i] = 1; TimKiem(Dinh+1); //Tiếm kiếm đỉnh kế tiếp L[Dinh] = 0; DanhDau[i] = 0; } } } /*Chương trình chính*/ void main() { clrscr(); Doc_File(); KhoiTao(); cout<<"Duong Di Nguoi Khach"; TimKiem(1); //Tìm kiếm từ đỉnh thứ 2 của đồ thị if(Dem==0) cout<<" Khong Co"; delete*A,DanhDau,L; getch(); } Biên Soạn: Đào Anh Pha Trang 34 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 7 Cĩ n thành phố biết rằng đường đi giữa các thành phố (nếu cĩ) là đường đi hai chiều. Sơ đồ mạng lưới giao thơng của n thành phố cho bởi ma trận A[i,j] trong đĩ: - A[i,j] là độ dài đường đi từ thành phố i đến thành phố j. - A[i,j] = 0 nếu khơng cĩ đường đi từ thành phố i đến thành phố j. - A[i,j] = A[j,i] - A[i,j] nguyên, khơng âm. Hãy xác định đường đi ngắn nhất từ thành phố D đến thành phố C. Dữ liệu vào: đồ thị đã liên thơng và cho trong file Bai7.inp với nội dung - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: xuất ra màn hình đường đi ngắn nhất từ đỉnh D đến C và giá trị đường đi ngắn nhẩt tìm được. Ví dụ: Bai7.inp Kết quả: 6 DUONG DI NGAN NHAT LA: 5 1 6 1->2->4->6 0 1 2 0 0 0 1 0 2 2 3 0 2 2 0 5 4 0 0 2 5 0 3 2 0 3 4 3 0 4 0 0 0 2 4 0 Bai7.inp Kết quả: 6 DUONG DI NGAN NHAT LA: 8 1 6 1->2->4->6 0 1 4 0 0 0 1 0 2 6 5 0 4 2 0 7 3 0 0 6 7 0 0 1 0 5 3 0 0 3 0 0 0 1 3 0 HƯỚNG DẪN THUẬT TỐN Sử dụng thuật tốn DIJKSTRA tìm đường đi ngắn nhất. Biên Soạn: Đào Anh Pha Trang 35 Giáo Trình Thực Hành Lý Thuyết Đồ Thị CHƯƠNG TRÌNH MẪU #include #include #include #include #define FileIn "Bai7.inp" /*Đọc file dữ liệu bài tốn*/ void Doc_File(int**A, int &n, int &D, int &C){ FILE*f = fopen(FileIn,"rb"); fscanf(f,"%d%d%d",&n,&D,&C); cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<D<<" "<<C<<endl; *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<A[i][j]<<" "; } cout<<endl; } fclose(f); D--; C--; } /*Thuật tốn Dijkstra tìm đường đi ngắn nhẩt từ đỉnh D đến đỉnh C*/ void Dijkstra(int **A, int n, int D, int C) { char *DanhDau = new char[n]; int *Nhan = new int[n]; int *Truoc = new int[n]; int XP, min; for(int i=0; i<n; i++){ Nhan[i] = MAXINT; DanhDau[i] = 0; Truoc[i] = D; } Biên Soạn: Đào Anh Pha Trang 36 Giáo Trình Thực Hành Lý Thuyết Đồ Thị Nhan[D] = 0; DanhDau[D] = 1; XP = D; while(XP != C){ for(int j=0; j<n; j++) if(A[XP][j]>0 && Nhan[j]>A[XP][j]+Nhan[XP] && DanhDau[j]==0) { Nhan[j] = A[XP][j]+Nhan[XP]; Truoc[j] = XP; } min = MAXINT; for(j = 0; j<n; j++) if(min>Nhan[j]&& DanhDau[j]==0){ min = Nhan[j] ; XP = j ; } DanhDau[XP] = 1; } cout<<”Duong Di Ngan Nhat La:”<<Nhan[C]<<endl; cout<<C+1<<” <- “<<Truoc[C]+1; i = Truoc[C]; while(i!=D){ i = Truoc[i]; cout<<” <- “<<i+1; } } /*Chương trình chính*/ void main() { int**A,n,Dau,Cuoi; Doc_File(A,n,Dau,Cuoi); Dijkstra(A,n,Dau,Cuoi); delete*A; getch(); } Biên Soạn: Đào Anh Pha Trang 37 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 8 Một cơng ty cần thay tồn bộ hệ thống dây điện cho n phịng làm việc. Cho biết sơ đồ điện hiện cĩ của n căn phịng này được biều diễn bằng ma trận A[i,j] trong đĩ: - A[i,j]=A[j,i] chính là chiều dài dây điện nối liền giữa hai phịng i và j. - A[i,j] = A[j,i] = 0 nếu i khơng nối liền với j. Hãy lập trình tính độ dài cuả dây dẫn cần sử dụng sao cho cả n phịng điều cĩ điện và số lượng này là ít nhất. Chú ý: đồ thị đã cho là liên thơng. Dữ liệu vào: cho trong file Bai8.inp (đồ thị cho đã liên thơng). - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng i+1 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: lưu trong file Bai8.out với nội dung sau: - Dịng đầu lưu độ dài dây dẫn nhỏ nhất - Các dịng cịn lại lưu đường đi cần nối điện giữa đỉnh i nối với đỉnh j cĩ trọng số A[i,j] (i -> j = A[i][j]). Bai8.inp Bai8.out 5 0 3 3 2 2 3 0 2 3 8 3 2 0 1 4 2 3 1 0 4 2 8 4 4 0 7 4 – 3 3 – 2 4 – 1 1 – 5 Bai8.inp Bai8.out 8 0 2 3 4 0 0 0 0 2 0 3 0 4 0 0 0 3 3 0 7 6 5 2 0 4 0 7 0 0 0 3 0 0 4 6 0 0 4 0 8 0 0 5 0 4 0 1 6 0 0 2 3 0 1 0 5 0 0 0 0 8 6 5 0 20 1 - 2 1 - 3 3 - 7 7 - 6 7 - 4 2 - 5 7 - 8 HƯỚNG DẪN THUẬT TỐN ¾ Thuật tốn Prim tìm cây phủ tối tiểu. ¾ Thuật tốn Kruskal tìm cây phủ tối tiểu. 1) Thuật tốn Prim tìm cây phủ tối tiểu. Bước 1: Xuất phát từ đỉnh k bất kỳ (thơng thường chon k là đỉnh đầu tiên) chọn một cạnh cĩ trọng số nhỏ nhất của đồ thị (min{A[k][j]}j=1..n) ta đánh dấu 2 đỉnh đi qua cạnh Biên Soạn: Đào Anh Pha Trang 38 Giáo Trình Thực Hành Lý Thuyết Đồ Thị đĩ và số cạnh tìm được là 1. Chuyển sang bước 2. Bước 2: Tìm cạnh nhỏ nhất của đồ thị với điều kiện cạnh tìm được phải cĩ 1 đỉnh chưa đánh dấu và 1 đỉnh đã đánh dấu (min{A[i][j]}j=1..n, i=1..n sao cho i đánh đấu và j chưa đánh dấu) để tránh trường hợp tạo thành chu trình. Ta tăng số cạnh tìm được lên 1 và chuyển sang bước 3. Bước 3: Nếu số cạnh tìm được bằng n-1 kết thúc thuật tốn, ngược lại quay về bước 2. 2) Thuật tốn Kruskal tìm cây phủ tối tiểu. Bước 0: Khởi tạo tập cạnh tìm được là rỗng. Chuyển sang bước 1. Bước 1: Chọn một cạnh cĩ trọng số nhỏ nhất sao cho khi đưa cạnh này vào tập cạnh tìm được khơng tạo thành chu trình. Tăng số cạnh tìm được lên 1và chuyển sang bước 2. Bước 2: Nếu số cạnh tìm được bằng n-1 thuật tốn kết thúc, ngược lại quay về bước 1. HƯỚNG DẪN CÀI ĐẶT 1) Thuật tốn Prim tìm cây phủ tối tiểu. Ta tổ chức mảng 1 chiều D để đánh dấu . Nếu D[i]=1 đỉnh i được đánh dấu và D[i]=0 nếu i chưa được đánh dấu. Bước 1: Tìm min{A[i][j]}j=1..n, i=1..n. Sau đĩ gán D[i]=D[j]=1 (đánh dấu 2 đỉnh i,j) và cho số cạnh tìm được bằng 1 (Dem=1). Bước 2: Tìm min{A[i][j]}j=1..n, i=1..n với điều kiện D[i]=1 và D[j]=0. Sau đĩ gán D[j]=1 (đánh dấu đỉnh j vừa tìm được) và tăng số cạnh lên 1 (Dem++). Bước 3: Nếu Dem = n-1 thì thuật tốn kết thúc. 2) Thuật tốn Kruskal tìm cây phủ tối tiểu. Ta tổ chức mảng 1 chiều D để đánh dấu . Nếu D[i]=T thì đỉnh i thuộc vào cây thứ T, D[i] = 0 thì đỉnh i chưa thuộc vào cây. Bước 1: Tìm min{A[i][j]}j=1..n, i=1..n ngoại trừ điều kiện D[i]=D[j]≠0. Vì khi thỏa mãn điều kiện trên đỉnh i,j đã thuộc vào một cây do đĩ khi lấy thêm cạnh này chúng sẽ tạo thành chu trình. Đỉnh i,j tìm được thoả mãn một trong các trường hợp sau: - Nếu D[i]=D[j]=0, đỉnh i,j chưa thuộc vào cây nên khi lấy 2 đỉnh này vào tập cạnh ta cho chúng thuộc vào 1 cây mới. Nghĩa là số cây T++ và D[i]=D[j]=T. - Nếu D[i]=0 và D[j]≠0, đỉnh i chưa thuộc vào cây và j đã thuộc vào cây. Ta lấy đỉnh i vào cây tương ứng với cây của đỉnh j. Nghĩa là gán D[i]=D[j]. - Nếu D[i]≠0 và D[j]=0, đỉnh j chưa thuộc vào cây và i đã thuộc vào cây. Ta lấy đỉnh j vào cây tương ứng với cây của đỉnh i. Nghĩa là gán D[j]=D[i]. - Nếu D[i]≠D[j] và D[i]≠0 và D[j]≠0, đỉnh i thuộc vào cây và đỉnh j cũng thuộc vào cây nhưng cây i và j là 2 cây khác nhau. Ta tiến hành ghép cây nghĩa là ghép 2 cây chứa i,j thành 1 cây mới. Temp = D[i] for(int i=0 ; i<n ; i++) Biên Soạn: Đào Anh Pha Trang 39 Giáo Trình Thực Hành Lý Thuyết Đồ Thị if(D[i]==Temp) D[i]=D[j] Tăng số cạnh tìm được lên 1 (Dem++). Bước 2: Nếu Dem = n-1 thì thuật tốn kết thúc. Chú ý: trong qua trình tìm cĩ thể tạo thành rất nhiều cây nhưng kết quả tìm được cuối cùng là một cây thơng qua quá trình ghép cây. CHƯƠNG TRÌNH MẪU 1) Thuật tốn Prim tìm cây phủ tối tiểu. #include #include #include #include #define FileInt "Bai8.inp" #define FileOut "Bai8.out" /*Lưu lại những cạnh đã đi qua x->y*/ typedef struct Egde { int x,y; }; /*Doc dữ liệu từ file*/ void Doc_File(int **A,int &n){ FILE*f = fopen(FileInt,"rb"); fscanf(f,"%d",&n); *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); } } fclose(f); } /*Ghi dữ liệu ra file*/ void Ghi_File(Egde*L,int n,int Sum) { FILE*f = fopen(FileOut,"wb"); fprintf(f,"%d\n",Sum); for(int i =0; i<n-1; i++) fprintf(f,"%d - %d\n",L[i].x+1,L[i].y+1); fclose(f); } /*Thuật tốn Prim*/ Biên Soạn: Đào Anh Pha Trang 40 Giáo Trình Thực Hành Lý Thuyết Đồ Thị void Prim(int **A, int n){ char *D = new char[n]; /*Dánh dấu đỉnh*/ Egde *L = new Egde[n-1]; /*Lưu đường đi */ int min = MAXINT, Dem = 0, Sum = 0; /*Khoi tạo giá trị cho mảng đánh dấu*/ for(int i=0; i<n; i++) D[i]=0; /*Tìm cạnh nhỏ nhất đầu tiên xuất phát từ đỉnh 1*/ for(int j=1; j<n; j++) if(min>A[0][j] && A[0][j]!=0){ min = A[0][j]; L[0].y = j; } L[0].x = 0; D[0] = D[L[0].y] = 1; Sum+=min; Dem++; /*Thực hiện cho đến khi số cạnh tìm được là n-1 cạnh*/ do{ min = MAXINT; for( i=0; i<n; i++) if(D[i]==1) for( j=0; j<n; j++) if(A[i][j]>0 && min>A[i][j] && D[j]==0){ min = A[i][j]; L[Dem].x = i; L[Dem].y = j; } Sum+=min; D[L[Dem].y] = 1; Dem++; } while(Dem<n-1); Ghi_File(L,n,Sum); /*Ghi kết quả tìm được vào file*/ } /*Chương trình chính*/ void main() { int **A,n; Doc_File(A,n); Prim(A,n); delete *A; } Biên Soạn: Đào Anh Pha Trang 41 Giáo Trình Thực Hành Lý Thuyết Đồ Thị 2) Thuật tốn Kruskal tìm cây phủ tối tiểu. void Kruskal(int **A, int n){ char *D = new char[n]; Egde *L = new Egde[n-1]; int min, Dem = 0, Sum = 0, T = 0, Temp; for(int i=0; i<n; i++) D[i] = 0; do{ min = MAXINT; for( i=0; i<n; i++) for(int j=0; j<n; j++) if(A[i][j]>0 && min>A[i][j]&& !(D[i]!=0 && D[i]==D[j])) { min = A[i][j]; L[Dem].x = i; L[Dem].y = j; } /*Tạo ra cây mới*/ if(D[L[Dem].x] ==0 && D[L[Dem].y] == 0){ T++; D[L[Dem].x] = D[L[Dem].y] = T; } /*Đưa đỉnh tương ứng vào cây*/ if(D[L[Dem].x] == 0 && D[L[Dem].y] != 0) D[L[Dem].x] = D[L[Dem].y]; /*Đưa đỉnh tương ứng vào cây*/ if(D[L[Dem].x] != 0 && D[L[Dem].y] == 0) D[L[Dem].y] = D[L[Dem].x]; /*Ghép 2 cây thành 1 cây mới*/ if(D[L[Dem].x] != D[L[Dem].y] && D[L[Dem].y]!=0) { Temp = D[L[Dem].x]; for( i=0; i<n; i++) if(Temp==D[i]) D[i]=D[L[Dem].y]; } Sum+=min; Dem++; } while(Dem<n-1); Ghi_File(L,n,Sum); } Biên Soạn: Đào Anh Pha Trang 42 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 9 Cĩ n thành phố được đánh số từ 1 đến n. Mạng lưới giao thơng giữa các thành phố là đường hai chiều. Trên đường đi (nếu cĩ) từ thành phố i đến thành phố j, người ta khơng được mang quá A[i,j] đơn vị hàng. Nếu khơng cĩ đường đi từ thành phố i đến thành phố j thì xem như A[i,j] = 0. Cần vận chuyển hàng từ thành phố D đến thành phố C. Hãy thiết lập kế hoạch vận chuyển sao cho khối lượng hàng vận chuyển là nhiều nhất. Dữ liệu vào: đồ thị đã liên thơng và cho trong file Bai9.inp với nội dung - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: xuất ra màn hình kế hoạch vận chuyển từ đỉnh D đến C và giá trị đường đi ngắn nhẩt tìm được. Ví dụ: Bai9.inp Kết quả: 6 KHOI LUONG VAN CHUYEN NHIEU NHAT LA: 2 1 6 1->3->4->6 0 1 2 0 0 0 1 0 2 2 3 0 2 2 0 5 4 0 0 2 5 0 3 2 0 3 4 3 0 4 0 0 0 2 4 0 Bai9.inp Kết quả: 6 KHOI LUONG VAN CHUYEN NHIEU NHAT LA: 3 1 6 1->3->4->2->5->6 0 1 4 0 0 0 1 0 2 6 5 0 4 2 0 7 3 0 0 6 7 0 0 1 0 5 3 0 0 3 0 0 0 1 3 0 Biên Soạn: Đào Anh Pha Trang 43 Giáo Trình Thực Hành Lý Thuyết Đồ Thị HƯỚNG DẪN THUẬT TỐN Sử dụng phương pháp tối ưu theo từng đỉnh giống thuật tốn DIJKSTRA. HƯỚNG DẪN CÀI ĐẶT Khởi tạo: - Mọi nhãn ban đầu bằng vơ cùng. - Tất cả các đỉnh chưa được đánh dấu - Trước mọi đỉnh là đỉnh đầu. - Đánh dấu đỉnh xuất phát. Xét đỉnh xuất phát là đỉnh XP: - Nếu A[XP][j]>0, j chưa được đánh dấu và Nhan[j] = vơ cùng thì: Nhan[j] = min{Nhan[XP],A[XP][j]} Truoc[j] = XP - Nếu A[XP][j]>0, j chưa được đánh dấu, Nhan[j] khác vơ cùng và min{Nhan[XP],A[XP][j]}>Nhan[j] thì: Nhan[j] = min{Nhan[XP],A[XP][j]} Trước[j] = XP Xét đỉnh xuất phát tiếp theo: Đỉnh xuất phát tiếp theo là đỉnh chưa được đánh dấu và nhãn của đỉnh phải lớn nhất nhưng khác vơ cùng. Khi chọn được đỉnh xuất phát ta phải đánh dấu đỉnh XP. Minh họa thuật tốn: Xét đồ thị dưới đây, hãy lập kế hoạch vận chuyển hàng nhiều nhất từ đỉnh 1 đến đỉnh 6. Khởi tạo: Đỉnh 1 2 3 4 5 6 Nhãn ∞ ∞ ∞ ∞ ∞ ∞ Đánh dấu 1* 0 0 0 0 0 Trước 1 1 1 1 1 1 Biên Soạn: Đào Anh Pha Trang 44 Giáo Trình Thực Hành Lý Thuyết Đồ Thị - Xuất phát là đỉnh 1: dánh dấu đỉnh 1. Đỉnh 1 2 3 4 5 6 Nhãn ∞ 1 2 ∞ ∞ ∞ Đánh dấu 1* 0 0 0 0 0 Trước 1 1 1 1 1 1 - Xuất phát là đỉnh 3: đánh dấu đỉnh 3 (đỉnh 3 là đỉnh cĩ nhãn lớn nhất khác vơ cùng và chưa được đánh dấu). Đỉnh 1 2 3 4 5 6 Nhãn ∞ 2 2 2 2 ∞ Đánh dấu 1 0 1* 0 0 0 Trước 1 3 1 3 3 1 - Xuất phát là đỉnh 2: đánh dấu đỉnh 2 (đỉnh 2 là đỉnh cĩ nhãn lớn nhất khác vơ cùng và chưa được đánh dấu). Đỉnh 1 2 3 4 5 6 Nhãn ∞ 2 2 2 2 ∞ Đánh dấu 1 1* 1 0 0 0 Trước 1 3 1 3 3 1 - Xuất phát là đỉnh 4: đánh dấu đỉnh 4 (đỉnh 4 là đỉnh cĩ nhãn lớn nhất khác vơ cùng và chưa được đánh dấu). Đỉnh 1 2 3 4 5 6 Nhãn ∞ 2 2 2 2 2 Đánh dấu 1 1 1 1* 0 0 Trước 1 3 1 3 3 4 - Xuất phát là đỉnh 5: đánh dấu đỉnh 5 (đỉnh 5 là đỉnh cĩ nhãn lớn nhất khác vơ cùng và chưa được đánh dấu). Đỉnh 1 2 3 4 5 6 Nhãn ∞ 2 2 2 2 2 Đánh dấu 1 1 1 1 1* 0 Trước 1 3 1 3 3 4 - Xuất phát là đỉnh 6: đánh dấu đỉnh 6. Đỉnh xuất phát bằng đỉnh đi đến nên thuật tốn kết thúc và trọng tải lớn nhất là 2, kế hoạch vận chuyển qua các con đường là: 6 — 4 — 3 — 1. Biên Soạn: Đào Anh Pha Trang 45 Giáo Trình Thực Hành Lý Thuyết Đồ Thị CHƯƠNG TRÌNH MẪU #include #include #include #include #define FileIn "Bai9.inp" /*Dọc file dữ liệu của bài tĩan*/ void Doc_File(int**A, int &n, int &D, int &C){ FILE*f = fopen(FileIn,"rb"); fscanf(f,"%d%d%d",&n,&D,&C); cout<<"Ma Tran Lien Ket Tuong Ung.\n"; cout<<D<<" "<<C<<endl; *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<A[i][j]<<" "; } cout<<endl; } fclose(f); D--; C--; } /*Thủ tục tìm đường đi vận chuyển hàng nhiều nhất*/ void VanChuyen(int **A, int n, int D, int C) { char *DanhDau = new char[n]; int *Nhan = new int[n]; int *Truoc = new int[n]; int XP, min,max; for(int i=0; i<n; i++){ Nhan[i] = MAXINT; DanhDau[i] = 0; Truoc[i] = D; } DanhDau[D] = 1; XP = D; while(XP != C){ for(int j=0; j<n; j++) if(A[XP][j]>0&&DanhDau[j]==0){ Biên Soạn: Đào Anh Pha Trang 46 Giáo Trình Thực Hành Lý Thuyết Đồ Thị if(Nhan[j]==MAXINT){ if(Nhan[XP]>A[XP][j]) Nhan[j] = A[XP][j]; else Nhan[j] = Nhan[XP]; Truoc[j] = XP; } if(Nhan[j]!=MAXINT){ if(Nhan[XP]>A[XP][j]) min = A[XP][j]; else min = Nhan[XP]; if(Nhan[j]<min){ Nhan[j] = min; Truoc[j] =XP; } } } max = 0; for(j=0; j<n; j++) if(Nhan[j]<MAXINT&&DanhDau[j]==0&&max<Nhan[j]){ max = Nhan[j]; XP = j; } DanhDau[XP] = 1; } cout<<"Van chuyen nhieu nhat la: "<<Nhan[C]; cout<<"\nCon duong van chuyen nhu sau:\n"; cout<<C+1<<" <- "<<Truoc[C]+1; i = Truoc[C]; while(i!=D){ i = Truoc[i]; cout<<" <- "<<i+1; } } /*Chương trình chính*/ void main() { clrscr(); int**A,n,Dau,Cuoi; Doc_File(A,n,Dau,Cuoi); VanChuyen(A,n,Dau,Cuoi); delete*A; getch(); } Biên Soạn: Đào Anh Pha Trang 47 Giáo Trình Thực Hành Lý Thuyết Đồ Thị BÀI TỐN 10 Cĩ n thành phố biết rằng đường đi giữa các thành phố là đường đi hai chiều. Sơ đồ mạng lưới giao thơng của n thành phố cho bởi ma trận A[i,j] trong đĩ: - A[i,j] là độ dài đường đi từ thành phố i đến thành phố j. - A[i,j] = 0 nếu khơng cĩ đường đi từ thành phố i đến thành phố j. - A[i,j] = A[j,i] - A[i,j] nguyên, khơng âm. Hãy xác định đường đi dài nhất từ thành phố D đến thành phố C với điều kiện thành phố đã qua khơng được đi lại. Dữ liệu vào:đồ thị đã liên thơng và cho trong file Bai10.inp - Dịng đầu ghi số n là số đỉnh của một đồ thị (0<n<100) - Dịng thứ hai lưu đỉnh D và đỉnh C. - Dịng i+2 ( ) chứa n số A[i,1],A[i,2]A[i,n] mỗi số cách nhau bởi một khoảng trắng. ni ≤≤1 Dữ liệu ra: xuất ra màn hình đường đi dài nhất từ đỉnh D đến C và giá trị đường đi ngắn nhẩt tìm được. Ví dụ: Bai10.inp Kết quả: 6 DUONG DI DAI NHAT LA: 16 1 6 1->2->4->3->5->6 0 1 2 0 0 0 1 0 2 2 3 0 2 2 0 5 4 0 0 2 5 0 3 2 0 3 4 3 0 4 0 0 0 2 4 0 Bai10.inp Kết quả: 6 DUONG DI DAI NHAT LA: 25 1 6 1->3->4->2->5->6 0 1 4 0 0 0 1 0 2 6 5 0 4 2 0 7 3 0 0 6 7 0 0 1 0 5 3 0 0 3 0 0 0 1 3 0 HƯỚNG DẪN THUẬT TỐN Sử dụng kỹ thuật tìm kiếm theo chiều sâu. Biên Soạn: Đào Anh Pha Trang 48 Giáo Trình Thực Hành Lý Thuyết Đồ Thị HƯỚNG DẪN CÀI ĐẶT Sử dụng kỹ thuật cài đặt tìm kiếm theo phương pháp đệ quy, khi tìm được 1 phương án thì lưu lại trạng thái của phương án ban đầu và so sánh với phương án mới tìm được, nếu phương án mới tốt hơn thì chọn phương án mới. CHƯƠNG TRÌNH MẪU include #include #include #define Filename "Bai10.inp" /*Khai báo các biến tồn cục*/ int*L,*L1; //Luu lai duong da di char*DanhDau; //Danh dau dinh da di int **A,n,D,C,Tong,Tong1,Canh1; /*Dọc file dữ liệu của bài tốn*/ void Doc_File() { FILE*f = fopen(Filename,"rb"); fscanf(f,"%d%d%d",&n,&D,&C); cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<D<<" "<<C<<endl; *A = new int [n]; for(int i =0;i<n;i++) { A[i] = new int [n]; for(int j =0;j<n;j++) { fscanf(f,"%d",&A[i][j]); cout<<A[i][j]<<" "; } cout<<endl; } fclose(f); D--; C--; } /*Khởi tạo ban đầu cho thủ tục tìm kiếm*/ void KhoiTao() { DanhDau = new char [n]; L = new int [n]; //Lưu đường đi tìm được L1 = new int [n]; //Lưu đường đi lớn nhất for (int i = 0; i<n; i++) { DanhDau[i] = 0; //Các đỉnh chưa được đánh dấu L[i] = 0; } DanhDau[D] = 1; //Dánh dấu đỉnh xuẩt phát L[0] = D; //Đường đi đầu tiên qua đỉnh đầu Biên Soạn: Đào Anh Pha Trang 49 Giáo Trình Thực Hành Lý Thuyết Đồ Thị Tong = 0; //Trong số đường đi Tong1 = 0; //Lưu lại trọng số lớn nhất của đường đi } /*In đường đi dài nhất tìm được*/ void InDuongDi() { cout<<"\nDUONG DI DAI NHAT:"<<Tong1<<endl<<D+1; for (int i = 1; i<Canh1; i++) cout "<<L1[i]+1; } /*Xử lý để lấy phương án tổt hơn*/ void XuLy(int Canh) { if(Tong>Tong1){ Tong1 = Tong; //Lưu lại trọng số tốt hơn Canh1 = Canh; //Lưu lại số cạnh đã đi qua for(int i =0; i<Canh; i++) L1[i] = L[i]; //Lưu lại đường đi tốt hơn } } /*Thủ tục tìm kiếm đệ quy*/ void TimKiem(int SoCanh) { if(L[SoCanh-1] == C) XuLy(SoCanh); else { for(int i = 0; i<n; i++) if( A[L[SoCanh-1]][i]>0 && DanhDau[i] == 0){ L[SoCanh] = i; DanhDau[i] = 1; Tong+=A[L[SoCanh-1]][i]; TimKiem(SoCanh+1); L[SoCanh] = 0; Tong-=A[L[SoCanh-1]][i]; DanhDau[i] = 0; } } } void main() { Doc_File(); KhoiTao(); TimKiem(1); if(Tong1==0) cout<<"\NKHONG CO DUONG DI"; else InDuongDi(); delete*A,DanhDau,L; getch(); } Biên Soạn: Đào Anh Pha Trang 50 Giáo Trình Thực Hành Lý Thuyết Đồ Thị THUẬT TỐN [] Kiểm tra tính liên thơng của đồ thị .............................................................................. [] Đếm số thành phần liên thơng của đồ thị .................................................................... [] Thuật tốn tìm mọi đường đi từ đỉnh D đến đỉnh C .................................................... [] Thuật tốn tìm một đường đi Euler.............................................................................. [] Thuật tốn tìm một đường đi Hamilton ....................................................................... [] Thuật tốn Dijkstra tìm đường đi ngắn nhất ................................................................ [] Thuật tốn Prim tìm cây phủ tối tiểu ........................................................................... [] Thuật tốn Kruskal tìm cây phủ tối tiểu ...................................................................... [] Thuật tốn đệ quy tìm mọi đường đi Euler.................................................................. [] Thuật tốn đệ quy tìm mọi đường đi Hamilton ........................................................... [] Thuật tốn tốn khử đệ quy tìm mọi đường đi Euler................................................... [] Thuật tốn tốn khử đệ quy tìm mọi đường đi Hamilton ............................................ Biên Soạn: Đào Anh Pha Trang 51

Các file đính kèm theo tài liệu này:

  • pdftailieu.pdf
Tài liệu liên quan