Trong khoa học máy tính, việc nghiên cứu về thuật toán có vai trò rấtquan trọng vì máy tính chỉ giải quyết được vấn đề khi đã có hướng dẫn giải rõràng và đúng. Nếu hướng dẫn giải sai hoặc không rõ ràng thì máy tính khôngthể giải đúng được bài toán. Thuật toán được định nghĩa là một dãy hữuhạn các bước không mập mờ và có thể thực thi được, quá trình hành độngtheo các bước này phải dừng và cho được kết quả như mong muốn. Để có thểlàm được một chương trình, dự án lớn nhất thiết phải cần thuật toán.Hiện nay có rất nhiều thuật toán để hỗ trợ chúng ta trong việc lập trình.Trong đó thuật toán quay lui, nguyên lý thứ tự và quy hoạch động rất đángđược chú ý. Vì vậy, em xin chọn đề tài “Ứng dụng thuật toán quay lui,nguyên lý thứ tự và quy hoạch động để giải một số bài toán điển hình”.
Trang 1MỤC LỤC
PHẦN I: MỞ ĐẦU 3
1.Giới thiệu đề tài 3
2 Mục đích yêu cầu của đề bài 3
2.1 Mục đích 3
2.2 Yêu cầu 3
3 Phương pháp nghiên cứu 3
PHẦN II: NỘI DUNG 5
1 Thuật toán Quay Lui 5
1.1 Giới thiệu thuật toán 5
1.1.1 Khái niệm 5
1.1.2 Ý tưởng 5
1.1.3 Demo 5
1.2 Bài toán 8 hậu 6
1.2.1 Giới thiệu 6
1.2.2 Ý tưởng – Phân tích 6
1.2.3 Thuật toán 7
1.2.4 Code demo 8
1.2.5 Kết quả 10
1.2.6 Nhận xét 11
2 Nguyên lý thứ tự 12
2.1 Giới thiệu 12
Trang 22.2.1 Giới thiệu 13
2.2.2 Ý tưởng – Phân tích 13
2.2.3 Thuật toán 14
2.2.4 Code demo 16
2.2.5 Kết quả 21
2.2.6 Nhận xét 22
3 Quy hoạch động 22
3.1 Giới thiệu 22
3.2 Bài toán tam giác số 23
3.2.1 Giới thiệu 23
3.2.2 Ý tưởng – Phân tích 24
3.2.3 Thuật toán 24
3.2.4 Code demo 24
3.2.5 Kết quả 26
3.2.6 Nhận xét 26
PHẦN III – KẾT LUẬN 27
Giáo viên hướng dẫn 27
Ths Trịnh Thị Phú 27
Sinh viên thực hiện 27
Hoàng Năng Hưng 27
TÀI LIỆU THAM KHẢO 28
Trang 3PHẦN I: MỞ ĐẦU 1.Giới thiệu đề tài
Trong khoa học máy tính, việc nghiên cứu về thuật toán có vai trò rất quan trọng vì máy tính chỉ giải quyết được vấn đề khi đã có hướng dẫn giải rõ ràng và đúng Nếu hướng dẫn giải sai hoặc không rõ ràng thì máy tính không thể giải đúng được bài toán Thuật toán được định nghĩa là một dãy hữu hạn các bước không mập mờ và có thể thực thi được, quá trình hành động theo các bước này phải dừng và cho được kết quả như mong muốn Để có thể làm được một chương trình, dự án lớn nhất thiết phải cần thuật toán
Hiện nay có rất nhiều thuật toán để hỗ trợ chúng ta trong việc lập trình Trong đó thuật toán quay lui, nguyên lý thứ tự và quy hoạch động rất đáng được chú ý Vì vậy, em xin chọn đề tài “Ứng dụng thuật toán quay lui, nguyên lý thứ tự và quy hoạch động để giải một số bài toán điển hình”
2 Mục đích yêu cầu của đề bài
2.1 Mục đích
Đề tài này giúp em củng cố, nâng cao kiến thức về môn học cấu trúc dữ liệu và giải thuật Từ đó hiểu sâu hơn và vận dụng vào trong các bài toán số liệu thực tế đồng thời thông qua việc làm đề tài này giúp em biết được các phương pháp nghiên cứu một vấn đề nhỏ nào đó
2.2 Yêu cầu
Dùng ngôn ngữ lập trình C/C++ để cài đặt chương trình Với dữ liệu được nhập vào từ bàn phím
3 Phương pháp nghiên cứu
Tham khảo tài liệu: cấu trúc dữ liệu và giải thuật, trên mạng…
Tìm hiểu thực tiễn, thực tế, quy cách, nhu cầu của bài toán
Trang 4 Xin ý kiến, hướng dẫn của giáo viên hướng dẫn
Trang 5PHẦN II: NỘI DUNG
1 Thuật toán Quay Lui
1.1 Giới thiệu thuật toán
1 đáp số, ngược lại tiếp tục xác định xi+1. Khi đã xét tất cả khả năng có thể của
xi, ta lần ngược lại bước trước để xác định một khả năng kế tiếp của xi – 1
Trang 61.2.2 Ý tưởng – Phân tích
Lời giải của bài toán là một cách xếp tám quân hậu trên bàn cờ sao cho không có hai quân nào đứng trên cùng hàng, hoặc cùng cột hoặc cùng đường chéo Bài toán tám quân hậu có thể tổng quát hóa thành bài toán đặt n quân hậu trên bàn cờ n × n (n ≥ 4)
Do yêu cầu của bài toán là tìm các vị trí để đặt n quân hậu nên thay vì sử dụng mảng 2 chiều ta chỉ cần sử dụng mảng một chiều h[0 n - 1] trong
đó h[i] thuộc đoạn [0 n - 1] là vị trí (cột) của quân hậu thứ i Với ví dụ ở trên hình mảng h sẽ là: [3 6 2 7 2 4 1 5] (quân hậu hàng 0 sẽ ở cột 3, quân hậu hàng 1 sẽ ở cột 6,
Trong quá trình thử (đệ quy - quay lui), ta sẽ lần lượt đặt quân hậu tại một số vị trí trong bàn cờ Mỗi lần thử đặt một quân hậu tại một ô nào đó thì phải đánh dấu các ô trong hàng, cột và hai đường chéo đi qua ô vừa đặt để các lần thử tiếp theo không đặt quân hậu nào khác vào các ô này (vì chũng đã bị khống chế bởi 1 quân hậu)
Trang 7Để tiện trong việc trình bày ý tưởng cũng như lập trình, ta sẽ ký hiệu các đường chéo chính (theo hướng tây nam - đông bắc) và các đường chéo phụ (theo hướng tây bắc - đông nam) như hình 2 Ta thấy ô (i, j) sẽ thuộc:
Đường chéo chính có số thứ tự là (i + j)
Đường chéo phụ có số thứ tự là (i - j + n)
Mỗi lần đặt một con hậu tại vị trí (i, j) nào đó, ta phải đánh dấu các ô trên hàng i, cột j, đường chéo chính (i + j) và đường chéo phụ (i - j + n) để sau này không được đặt con hậu nào vào những vị trí này Do đó, thay vì phải lưu phần đánh dấu cho tất cả các ô trên bàn cờ (nghĩa là cần một mảng n x n), ta chỉ cần đánh dấu cho các hàng, cột, đường chéo chính và đường chéo phụ tương ứng (nghĩa là cần hai mảng một chiều n phần tử để đánh dấu các hàng, cột và cần thêm hai mảng một chiều 2n+1 phần tử để đánh dấu các đường chéo)
B2.3.1: In ra ký tự “ – “ Xuống dòng
Trang 8B3.1.1.4: Ngược lại thì try(i + 1) B3.1.1.5: cot[j] = 1, cheoChinh[i + j] = 1, cheoPhu[j - i + n] = 1;
Trang 11 Nếu số dư r là 3 hoặc 9, chuyển 2 xuống cuối danh sách
Bổ sung lần lượt các số lẻ từ 1 đến n vào cuối danh sách, nhưng nếu r là 8, đổi chỗ từng cặp nghĩa là được 3, 1, 7, 5, 11, 9, …
Nếu r = 2, đổi chỗ 1 và 3, sau đó chuyển 5 xuống cuối danh sách
Trang 12 Nếu r = 3 hoặc 9, chuyển 1 và 3 xuống cuối danh sách
Lấy danh sách trên làm danh sách chỉ số cột, ghép vào danh sách chỉ số dòng theo thứ tự tự nhiên ta được một lời giải của bài toán
Bài toán tám quân hậu có 92 lời giải khác nhau Nếu không phân biệt các lời giải là ảnh của nhau qua phép đối xứng, phép quay bàn cờ thì chúng chỉ có
12 lời giải đơn vị Với code ở bên trên ta hoàn toàn có thể chuyển thành bài toán xếp hậu tổng quát bằng cách thay giá trị của n
2 Nguyên lý thứ tự
2.1 Giới thiệu
Thuật giải Heuristic là một sự mở rộng khái niệm thuật toán Nó thể hiện cách giải bài toán với các đặc tính sau :
Thường tìm được lời giải tốt (nhưng không chắc là lời giải tốt nhất)
Giải bài toán theo thuật giải Heuristic thường dễ dàng và nhanh chóng đưa ra kết quả hơn so với giải thuật tối ưu, vì vậy chi phí thấp hơn
Thuật giải Heuristic thường thể hiện khá tự nhiên, gần gũi với cách suy nghĩ và hành động của con người
Có nhiều phương pháp để xây dựng một thuật giải Heuristic, trong đó người ta thường dựa vào một số nguyên lý cơ sở như sau :
Nguyên lý vét cạn thông minh:
Trong một bài toán tìm kiếm nào đó, khi không gian tìm kiếm lớn, ta thường tìm cách giới hạn lại không gian tìm kiếm hoặc thực hiện một kiểu dò tìm đặc biệt dựa vào đặc thù của bài toán để nhanh chóng tìm ra mục tiêu
Nguyên lý tham lam (Greedy):
Trang 13Lấy tiêu chuẩn tối ưu (trên phạm vi toàn cục) của bài toán để làm tiêu chuẩn chọn lựa hành động cho phạm vi cục bộ của từng bước (hay từng giai đoạn) trong quá trình tìm kiếm lời giải
Ðể gia công một công việc Ji trên một máy bất kỳ ta cần dùng một thời gian tương ứng là ti Nhiệm vụ của công ty là phải làm sao gia công xong toàn bộ n chi tiết trong thời gian sớm nhất
2.2.2 Ý tưởng – Phân tích
Xây dựng một thuật toán để tìm một phương án tối ưu L0 cho bài toán này là một bài toán khó, đòi hỏi các kỹ thuật phức Bây giờ ta xét đến một thuật giải Heuristic rất đơn giản để giải bài toán này Các bước thực hiện :
Sắp xếp các công việc theo thứ tự giảm dần về thời gian gia công
Lần lượt sắp xếp các việc theo thứ tự đó vào máy còn dư nhiều thời gian nhất
Trang 14B4.2: In ra chỉ số công việc và thời gian công việc
B5: Viết một hàm hoán vị công việc
B5.1: Hoán vị thời gian công việc
B5.2: Hoán vị chỉ số công việc
B6: Viết hàm sắp xếp công việc:
B6.1: Duyệt i chạy từ 0 -> n – 2, i++
B6.1.1: Duyệt j chạy từ i + 1 -> soCongViec – 1, j++
B6.1.1.1: Gọi hàm hoán vị công việc
B7: Viết hàm khởi tạo máy:
B8: Viết hàm tìm máy có thời gian làm việc ít nhất:
Trang 15B8.2: Duyệt i chạy từ 1 -> soMay – 1, i++
B8.2.2: Nếu min > may[i].tongThoiGian thì:
min = may[i].tongThoiGian;
temp = i;
B8.3: Trả về temp
B9: Viết hàm chia công việc cho các máy:
B9.1: Duyệt i chạy từ 0 -> soCongViec – 1, i++
B9.1.1: Chọn máy có thời gian làm việc ít nhất
B9.1.2: Thêm các công việc tiếp theo
B10: Viết hàm xuất kết quả:
B10.1: Gán max = may[0].tongThoiGian;
B10.2: Duyệt i chạy từ 0 -> soMay, i++
B10.2.1: Nếu max < may[i].tongThoiGian thì gán lại
B10.2.2: In ra tổng thời gian thực hiện và tổng thời gian hoàn thành
B11: Viết hàm main():
B11.1: Nhập số lượng máy, công việc:
B11.2: Gọi lần lượt các hàm khoiTaoMay, nhapCongViec, sapXepCongViec, xuatCongViec, chiaCongViec, xuatKetQua
Trang 16// Nhap thoi gian cho cac cong viec
void nhapCongViec(congViec cV[], int soCongViec)
Trang 17}
}
// Xuat thong tin cac cong viec
void xuatCongViec(congViec cV[], int soCongViec)
Trang 18int min = may[0].tongThoiGian;
for(i = 1; i < soMay; i++)
Trang 19int max = may[0].tongThoiGian;
for(i = 0; i < soMay; i++)
{
if(max < may[i].tongThoiGian)
max = may[i].tongThoiGian;
std::cout << std::endl << "May " << i + 1 << ":";
std::cout << std::endl << "Tong thoi gian thuc hien: " << may[i].tongThoiGian;
std::cout << std::endl <<"Thuc hien cac cong viec : ";
Trang 20viec la : " << max << " h" << std::endl;
int soMay, soCongViec;
std::cout << "Bai toan phan viec" << std::endl;
Trang 21Đây là 1 kết quả từ màn hình Console:
Nếu trường hợp có 3 máy P1, P2, P3 và 6 công việc với thời gian là t1 = 2,
t2 = 5, t3 = 8, t4 = 1, t5 = 5, t6 = 1 ta có một phương án phân công như sau :
Trang 222.2.6 Nhận xét
Phướng án kia đúng, nhưng vẫn chưa tối ưu hết mức Nếu gọi T* là thời gian để gia công xong n chi tiết máy do thuật giải Heuristic đưa ra và T0 thời gian tối ưu thì người ta đã chứng minh được rằng:
Trong trường hợp M lớn thì tỷ số 1/ M xem như bằng 0 Như vậy, sai
số tối đa là 33% Tuy nhiên, khó tìm ra được những trường hợp mà sai số đúng bằng giá trị cực đại, dù trong trường hợp xấu nhất Thuật giải Heuristic trong trường hợp này rõ ràng đã cho chúng ta những lời giải tương đối tốt
3 Quy hoạch động
3.1 Giới thiệu
Trong quá trình học tập, chúng ta gặp rất nhiều các bài tập về Toán - Tin Các bài tập dạng này rất phong phú và đa dạng Thực tế chưa có thuật toán hoàn chỉnh có thể áp dụng cho mọi bài toán Tuy nhiên người ta đã tìm ra một
số thuật toán chung như chia để trị, tham ăn, quay lui, Các thuật toán này có thể áp dụng để giải một lớp khá rộng các bài toán hay gặp trong thực tế Tiếp
Trang 23theo em muốn đề cập thêm một thuật toán nữa đó là thuật toán quy hoạch động Tư tưởng cơ bản của thuật toán là:
Để giải một bài toán ta chia bài toán đó thành các bài toán nhỏ hơn có thể giải một cách dễ dàng Sau đó kết hợp lời giải các bài toán con, ta có được lời giải bài toán ban đầu Trong quá trình giải các bài toán con đôi khi ta gặp rất nhiều kết quả trùng lặp của các bài toán con Để tăng tính hiệu quả, thay vì phải tính lại các kết quả đó, ta lưu chúng vào một bảng Khi cần lời giải của một bài toán con nào đó ta chỉ cần tim trong bảng, không cần tính lại
Tư tưởng của thuật toán quy hoạch động khá đơn giản Tuy nhiên khi áp dụng thuật toán vào trường hợp cụ thể lại không dễ dàng Khi giải bài toán bằng phương pháp này, chúng ta phải thực hiện hai yêu cầu quan trọng sau:
Tìm công thức truy hồi xác định nghiệm bài toán qua nghiệm các bài toán con nhỏ hơn
Với mỗi bài toán cụ thể, ta đề ra phương án lưu trữ nghiệm một cách hợp lý để từ đó có thể truy cập một cách thuận tiện nhất
3.2 Bài toán tam giác số
3.2.1 Giới thiệu
Hình dưới đây biểu diễn một tam giác số:
Hãy viết chương trình tính tổng lớn nhất các số trên con đường bắt đầu
từ đỉnh và kết thức ở đáy
Mỗi bước có thể đi chéo xuống phía trái hoặc đi chéo xuống phía phải
Số lượng hàng trong tam giác lớn hơn 1 nhưng bé hơn 100
Các số trong tam giác đều là các số nguyên từ 0 đến 99
Trang 243.2.2 Ý tưởng – Phân tích
Xem tam giác đề bài là một ma trận có dòng 1 là a[1][1], dòng 2 là a[2][1] a[2][2], dòng n là a[n][1], a[n][2],…, a[n][n] gọi F[i][j] là tổng lớn nhất của 1 đường đi từ đỉnh tam giác xuống ô a[i][j] , vì để đến a[i][j] chúng
ta có thể đi từ a[i - 1][j - 1] hoặc a[i - 1][j] nên công thức quy hoạch động là: F[i][j] = max(F[i - 1][j], F[i - 1][j - 1]) + a[i][j]
B4.2.2: Nếu a[i - 1][j - 1] > a[i - 1][j] thì
a[i][j] = a[i][j] + a[i - 1][j - 1]
B4.2.3: Ngược lại a[i][j] = a[i][j]+a[i - 1][j]
B4.3: Nhập a[i][i] và gán a[i][i] = a[i][i] + a[i - 1][i - 1]
Trang 27PHẦN III – KẾT LUẬN
Thông qua việc tìm hiểu về các thuật toán quay lui, nguyên lý thứ tự và quy hoạch động để viết chương trình của 1 số bài toán điển hình em đã rút ra được rất nhiều điều Từ cách xác định được giải thuật đến tư duy logic, cách làm một bài tiểu luận đúng và chuẩn và chương trình đã chạy thành công trên phần mềm Devcpp++ 5.11 và Code::Blocks 13.12 bằng ngôn ngữ C++
Có được kết quả trên là nhờ có sự dạy dỗ chu đáo của cô giáo Ths Trịnh Thị Phú trong quá trình truyền thụ kiến thức môn học phân tích thiết kế thuật toán đồng thời cô cũng là người hướng dẫn tận tình trong suốt quá trình thực hiện đề tài tiểu luận môn học này
Em xin chân thành cảm ơn !
Thanh Hóa, ngày….tháng 4 năm 2016
Giáo viên hướng dẫn
Ths Trịnh Thị Phú
Sinh viên thực hiện
Hoàng Năng Hưng
Trang 28TÀI LIỆU THAM KHẢO
[1] Bài tập môn học kỹ thuật lập trình – Trường Đại Học Bách Khoa Hà Nội [2] Giáo trình Giải thuật và Lập trình – Lê Minh Hoàng – Đại học Sư Phạm
Hà Nội 1999 – 2002
[3] Data Structures and Algorithms - Jennifer Rexford