SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HÓATRƯỜNG THPT TRIỆU SƠN 2 SÁNG KIẾN KINH NGHIỆM GIẢI CÁC DẠNG BÀI TOÁN LIỆT KÊ BẰNG PHƯƠNG PHÁP VÉT CẠN SỬ DỤNG THUẬT TOÁN QUAY LUI TRONG ÔN LUYỆN HỌC SINH
Trang 1SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HÓA
TRƯỜNG THPT TRIỆU SƠN 2
SÁNG KIẾN KINH NGHIỆM
GIẢI CÁC DẠNG BÀI TOÁN LIỆT KÊ BẰNG PHƯƠNG PHÁP VÉT CẠN SỬ DỤNG THUẬT TOÁN QUAY LUI TRONG ÔN LUYỆN HỌC SINH GIỎI MÔN TIN HỌC
Người thực hiện: Phạm Thị Biên Chức vụ: Giáo viên
SKKN thuộc bộ môn: Tin học
THANH HÓA NĂM 2014
Trang 2MỤC LỤC
A ĐẶT VẤN ĐỀ 3
I Lý do chọn đề tài 3
II Thực trạng của vấn đề 3
III Mục đích nghiên cứu 4
IV Đối tượng và phạm vi nghiên cứu 4
B GIẢI QUYẾT VẤN ĐỀ 5
I Cơ sở lý luận 5
II Biện pháp giải quyết vấn đề 5
1 Một số khái niệm 5
2 Một số dạng bài toán liệt kê 7
3 Một số bài toán tham khảo 19
III Kết quả thực nghiệm 19
C KẾT LUẬN VÀ ĐỀ XUẤT 20
I Kết luận 20
II Đề xuất, kiến nghị 20
Trang 3A ĐẶT VẤN ĐỀ
I LÝ DO CHỌN ĐỀ TÀI
Trong thời đại ngày nay, thế giới đang diễn ra quá trình tin học hóa trongnhiều lĩnh vực hoạt động của xã hội Tin học phát triển nhanh như vũ bão và đã trởthành một ngành khoa học đóng vai trò quan trọng không thể thiếu đối với sự pháttriển của xã hội
Nhiều quốc gia ý thức được tầm quan trọng của tin học và có những đầu tư lớnvào lĩnh vực này đặc biệt là lĩnh vực giáo dục nhằm đào tạo một đội ngũ tri thức trẻ
có nền tảng tin học vững vàng nhằm đáp ứng nhu cầu ngày càng cao của xã hội
Từ năm 2006 ngành giáo dục Việt Nam đã chính thức đưa bộ môn tin học vàotrong trường THPT nhằm mục đích phổ cập các kiến thức cơ bản về Tin học, ngoài
ra còn giúp học sinh có khả năng phân tích, tổng hợp, trừu tượng hóa, khái quát hóavấn đề, đặc biệt là phát triển khả năng tư duy Muốn vậy ngoài việc dạy đại trà,hướng nghiệp và dạy nghề cần tạo điều kiện cho học sinh có năng khiếu tin họcđược phát triển khả năng lập trình để giải quyết tốt các bài toán
Để có thể phát huy những tài năng tin học thông qua ôn luyện đội tuyển họcsinh giỏi, đòi hỏi người dạy phải tiếp cận với nhiều dạng bài toán khó và nắm vữngcác phương pháp giải quyết bài toán đó
Bài toán trong tin học thường rất đa dạng và phức tạp, mỗi bài toán có thể cónhiều phương pháp giải khác nhau Để có thể lựa chọn phương pháp thích hợp chobài toán, chúng ta có thể phân chia các bài toán thành các dạng bài toán tổng quan
và chỉ ra phương pháp giải cho các dạng bài toán đó
Bài toán liệt kê là một trong những lớp bài toán khó, thường xuất hiện trongcác đề thi học sinh giỏi cấp thành phố, cấp tỉnh hay cấp quốc gia Có nhiều phươngpháp giải lớp bài toán này nhưng phương pháp vét cạn là phù hợp nhất Chính vì
vậy nên tôi chọn đề tài: “Giải các dạng các bài toán liệt kê bằng phương pháp
vét cạn sử dụng thuật toán quay lui trong ôn luyện học sinh giỏi môn Tin học”
II THỰC TRẠNG CỦA VẤN ĐỀ
1 Thuận lợi
Do sự quan tâm và đầu tư của Bộ giáo dục và đào tạo nói chung và của trườngTHPT Triệu Sơn 2 nói riêng, về cơ sở vật chất môn Tin học đã có 1 phòng thựchành hoạt động tốt, ngoài ra còn có một số phòng máy chiếu projector hỗ trợ chogiáo viên trong công tác giảng dạy
Mặc dù môn Tin không phải là môn trọng điểm nhưng rất được Ban giám hiêuquan tâm động viên và tạo mọi điều kiện trong công tác giảng dạy và ôn luyện độituyển học sinh giỏi cũng như trong các công tác khác
Trong quá trình thực hiện đề tài tôi đã được các giáo viên trong tổ bộ môn tưvấn và hỗ trợ rất nhiều giúp tôi hoàn thành đề tài
Trang 42 Khó khăn
Ngôn ngữ lập trình Pascal là một môn học mới, cách học cũng hoàn toàn mới,
vì vậy khi tiếp cận với môn học này đa số học sinh thấy rất bỡ ngỡ Học các thaotác sử dụng hay dùng phương pháp học thuộc lòng không còn phù hợp nữa Lúcnày các em cần phải học cách tư duy logic, tìm thuật toán, và viết những dòng lệnhtrên máy tính chính xác đến từng đấu chấm, dấu phẩy
Với tâm lí thông thường các em học sinh coi tin học là môn phụ không quantrọng nên nhiều em chủ quan không dành đủ thời gian để học nên không hiểu bài
và dần bị mất căn bản Đây cũng là lí do mà nhiều em bị điểm kém, thậm chí là thilại, học lại bộ môn tin học mặc dù có thể các em học rất giỏi các môn học khác.Chính vì xem môn Tin là môn phụ nên khi lựa chọn đội tuyển ôn thi học sinhgiỏi giáo viên chúng tôi thường rất khó lựa chọn được những học sinh có năngkhiếu thực sự
Các dạng bài toán liệt kê là những bài toán khó, nếu người học có tư duy chưatốt thì người dạy sẽ rất khó khăn trong quá trình truyền đạt để giúp các em có thểhiểu được
3 Kết quả của thực trạng
Trước khi đi vào nghiên cứu và thực hiện đề tại này, tôi thường hướng dẫnhọc sinh tiếp cận với các bài toán liệt kê bằng cách cho bài tập và cách giải vớitừng bài mà không phân chia thành từng dạng cụ thể và thuật toán tổng quan chotừng dạng, dẫn đến học sinh rất mơ hồ, khó hiểu Kết quả khảo sát trong quá trìnhgiảng dạy và thông qua các bài kiểm tra như sau:
Nội dung cần nắm bắt Số lượng Tỉ lệ (%)
Vận dụng kiến thức đã học để làm tốt các
bài tập
Trang 5B GIẢI QUYẾT VẤN ĐỀ
I CƠ SỞ LÝ LUẬN
Bài toán liệt kê (hay còn gọi là bài toán cấu hình tổ hợp) là những bài toán khicho trước một tập các đối tượng, yêu cầu cho biết có bao nhiêu đối tượng thỏa mãnnhững điều kiện nhất định và chỉ rõ những cấu hình tìm được thỏa mãn những điềukiện trên
Bài toán liệt kê gồm có 3 dạng: tổ hợp, chỉnh hợp lặp và chỉnh hợp không lặp.Trong đó dạng bài toán chỉnh hợp không lặp thường hay xuất hiện nhiều nhất trongcác bài toán tin học
Sơ lược một số kiến thức đại số tổ hợp:
Cho S là một tập hữu hạn gồm n phần tử và số tự nhiên k Gọi X là tập hợpcác số nguyên dương từ 1 đến k: X= {1, 2, …, k}
Tổ hợp
Một tổ hợp chập k của n là một tập con k phần tử của tập n phần tử
Chẳng hạn tập {1,2,3,4} có các tổ hợp chập 2 là: {1,2}, {1,3, {1,4}, {2,3},{2,4}, {3,4} Vì trong tập hợp các phần tử không phân biệt thứ tự nên tập {1,2}cũng là tập {2,1} và do đó, ta coi chúng chỉ là một tổ hợp
Vậy số tổ hợp chập k của S gồm n phần tử là:
Chỉnh hợp lặp
Chỉnh hợp lặp chập k của n là một dãy k thành phần, mỗi thành phần là mộtphần tử của tập n phần tử, có xét đến thứ tự và không yêu cầu các thành phần khácnhau
Chỉnh hợp không lặp
Khác với chỉnh hợp lặp là các thành phần được phép lặp lại, tức là có thểgiống nhau, chỉnh hợp không lặp chập k của tập n phần tử cũng là một dãy k thànhphần lấy từ tập n phần tử có xét thứ tự nhưng các thành phần không được phépgiống nhau
Chẳng hạn có n người, một cách chọn ra k người để xếp thành một hàng làmột chỉnh hợp không lặp chập k của n
Số chỉnh hợp không lặp chập k của n phần tử là: n(n-1)(n-2)…(n-k+1)=
Để giải được bài toán liệt kê cần xác định được thuật toán tổng quan để trên cơ
sở đó xây dựng được tất cả các cầu hình liên quan
Khi đi vào giải quyết bài toán liệt kê, yêu cầu các cấu hình tìm được khôngđược lặp lại và không được bỏ sót cầu hình nào Để đáp ứng được yêu cầu trên thìphương pháp vét cạn sự lựa chọn thích hợp nhất
Trang 6II BIỆN PHÁP GIẢI QUYẾT VẤN ĐỀ
*Ưu điểm:
- Luôn đảm bảo tìm ra nghiệm chính xác
- Đòi hỏi rất ít bộ nhớ và cài đặt đơn giản
* Nhược điểm: Thời gian thực thi rất lớn, độ phức tạp thường bậc mũ
1.2 Quay lui (Backtracking)
Trong nhiều trường hợp, nghiệm của bài toán là dãy các phần tử được xácđịnh không theo luật tính toán nhất định Muốn tìm nghiệm, phải thực hiện từngbước theo dõi, tìm kiếm từng phần tử của nghiệm Giá trị mỗi phần tử có thể cónhiều khả năng khác nhau Để tìm giá trị gán cho mỗi phần tử, phải thử các khảnăng có thể xem chúng có thỏa mãn các điều kiện của bài toán hay không gọi là thửđúng/sai
Nếu có một lựa chọn được chấp nhận thì ghi nhớ các thông tin cần thiết cácbước thử tiếp theo.Trái lại, nếu không có một lựa chọn nào thích hợp thì làm lạibước trước, xoá bớt các ghi nhớ và quay về chu trình thử với các lựa chọn còn lại.Hành động này được gọi là quay lui (Back tracking) và các giải thuật thể hiệnphương pháp này gọi là các giải thuật quay lui
Tìm mọi nghiệm (gọi là vét cạn) bằng cách tiến dần, tìm kiếm các khả năng cóthể chấp nhận được cho từng phần tử của một nghiệm và biết quay lui khi khôngthể tiến được nữa Khi mọi phần tử của một nghiệm đã được gán giá trị thì kết thúcquá trình tìm một nghiệm, chuyển sang tìm nghiệm tiếp theo
Do thuật toán quay lui xây dựng trên cơ sở tìm kiếm dần, kết quả sau hìnhthành từ kết quả trước nên có thể sử dụng các hàm và các thủ tục đệ quy để thựchiện
Có thể so sánh các nghiệm tìm được để tìm nghiệm tối ưu
1.3 Thuật toán quay lui
Mô hình giải thuật quay lui có thể mô tả như sau:
Procedure Try (i);
Trang 7Begin
+ Lưu trạng thái của bài toán
+ Xác nhận giá trị đề cử cho bước i
+ Xác nhận trạng thái mới của bài toán sau khi chấp nhận đề cử + Nếu là bước cuối cùng thì hiện nghiệm và tăng biến đếm nghiệm Ngược lại thì Try(i+1)
+Trả lại trạng thái như trước khi chấp nhận đề cử
End;
End;
End;
Hoặc có thể viết dưới dạng sau:
Procedure Try (i);
+ Lưu trạng thái của bài toán
+ Xác nhận giá trị đề cử cho bước i
+ Xác nhận trạng thái mới của bài toán sau khi chấp nhận đề cử + Try(i+1)
+ Trả lại trạng thái như trước khi chấp nhận đề cử
Trang 8<ghi nhận trạng thái mới>;
If i=n then Update
Trên đây là các thuật toán vét cạn đối với bài toán tìm mọi cấu hình hay đếm
số cấu hình Trong trường hợp bài toán cần tìm một cấu hình, tìm cấu hình tối ưuthì thuật toán cũng tương tự, chỉ khác ở phần cập nhật (Update) khi sinh được mộtcấu hình mới
Chẳng hạn thủ tục Update đối với bài toán tìm nghiệm tối ưu:
2 Một số dạng bài toán liệt kê (cấu hình tổ hợp)
Bài toán tổ hợp yêu cầu tìm các đối tượng x có dạng là một vector thỏa mãncác điều kiện sau:
1 x gồm k phần tử: x=(x1,x2,…,xn)
2 Mỗi phần tử xi có thể nhận một trong tập các đối tượng a1,a2,…,an,
3 x thỏa mãn các ràng buộc có thể cho bởi hàm logic G(x)
Tùy từng trường hợp bài toán có thể yêu cầu tìm một nghiệm, tìm tất cả cácnghiệm hay đếm số nghiệm
2.1 Tổ hợp
Bài toán đặt ra cho chúng ta là hãy xác định tất cả các tổ hợp châp k của tập nphần tử Để đơn giản ta chỉ xét bài toán tìm các tổ hợp của tập các số nguyên từ 1đến n Đối với một tập hữu hạn bất kì, bằng cách đánh số thứ tự của các phần tử, tacũng đưa được về bài toán đối với tập các số nguyên từ 1 đến n
Nghiệm cần tìm của bài toán tìm các tổ hợp chập k của n phần tử phải thoảmãn các điều kiện sau:
1 Là một vector x =(x1,x2,…xk)
Trang 92 xi lấy giá trị trong tập {1,2,…n}
3 Ràng buộc: xi<xi+1 với mọi giá trị i từ 1 đến k-1
Có ràng buộc 3 là vì tập hợp không phân biệt thứ tự phần tử nên ta sắp xếp cácphần tử theo thứ tự tăng dần
Từ đó suy ra x[i-1] + 1 x[i] n-k+i (1 i k) Giả thiết có thêm số x[0] =
0 khi xét i=1 (x[0] là lính canh)
Về cấu trúc dữ liệu ta chỉ cần một mảng x để biểu diễn tổ hợp Ràng buộc đốivới giá trị x[i] là: x[i-1]< x[i] n-ki
Trang 102 xi lấy giá trị trong tập {1,2,…n}
3 Không có ràng buộc nào giữa các thành phần
Chú ý là cũng như bài toán tìm tổ hợp, ta chỉ xét đối với tập n số nguyên từ 1đến n Nếu tập hợp cần tìm chỉnh hợp không phải là tập các số nguyên từ 1 đến nthì ta có thể đánh số các phần tử của tập đó để đưa về tập các số nguyên từ 1 đến nĐối với bài toán sinh chỉnh hợp lặp chập k của n hoàn toàn không có ràngbuộc nào đối với cấu hình sinh ra Do đó, cấu trúc dữ liệu của ta chỉ gồm một mảng
Trang 11if i=k then Print(x)
Trang 12*Phân tích
Với bài toán này chúng ta sẽ dùng một mảng d[j] (j=1 2)chứa dấu cộng và trừ,một mảng x[i] (i=2 n) chứa các phép toán tương ứng được chèn vào giữa các số 1,2,…, N Vậy nghiệm bài toán được mô tả như sau:
Trang 14Nghiệm của bài toán tìm các chỉnh hợp không lặp chập k của tập n số nguyên
từ 1 đến n là các vector x thoả mãn các điều kiện:
1 x có k thành phần: x = (x1,x2,…xk)
2 Các giá trị xi lấy trong tập {1,2, n}
3 Ràng buộc: các giá trị xi đôi một khác nhau, tức là xi¹xj với mọi i¹j
Chỉnh hợp không lặp yêu cầu các phần tử phải khác nhau Để đảm bảo điều
đó, ngoài mảng x, ta sẽ dùng thêm một cấu trúc dữ liệu nữa là mảng d để đánh dấu.Khi một giá trị được chọn, ta đánh dấu giá trị đó, và khi chọn, ta chỉ chọn các giátrị chưa đánh dấu Mảng d sẽ là "trạng thái" của thuật toán Bạn đọc xem phần giả
mã dưới đây để thấy rõ hơn ý tưởng đó
Trang 152
2 3
1
2 1
3
Trang 16Ví dụ 2: Bài toán xếp hậu
Cho bàn cờ vua nxn Hãy xếp n con hậu lên bàn cờ sao cho không con nàokhống chế con nào Hai con hậu khống chế nhau nếu chúng ở trên cùng một hàng,một cột hoặc một đường chéo
*Phân tích
Để chuyển bài toán này về dạng chuẩn của bài toán tìm cấu hình tổ hợp, ta có
có nhận xét: mỗi con hậu phải ở trên một hàng và một cột Do đó ta coi con hậu thứ
i ở hàng i và nếu biết x[i] là cột đặt con hậu thứ i thì ta suy ra được lời giải Vậynghiệm của bài toán có thể coi là một vector x gồm n thành phần với ý nghĩa:
1 Con hậu thứ i được đặt ở hàng i và cột x[i]
2 x[i] lấy giá trị trong tập {1,2…n}
3 Ràng buộc: các giá trị x[i] khác nhau từng đôi một và không có 2 con hậu ởtrên cùng một đường chéo
Khác với những bài toán sinh các cấu hình đơn giản ở phần trước, sinh các cấuhình của bài toán xếp hậu đòi hỏi những phân tích chi tiết hơn về các điều kiện ràngbuộc
Ràng buộc thứ nhất là các giá trị x[i] phải khác nhau Ta có thể dùng mộtmảng đánh dấu như ở thuật toán sinh hoán vị để đảm bảo điều này
Ràng buộc thứ 2 là các con hậu không được nằm trên cùng một đường chéochính và phụ Các bạn có thể dễ dàng nhận ra rằng 2 vị trí (x1,y1) và (x2,y2) nằmtrên cùng đường chéo chính nếu:
x1-y1=x2-y2=const
Trang 17Tương tự, 2 vị trí (x1,y1) và (x2,y2) nằm trên cùng đường chéo phụ nếu:
x1y1=x2y2=const
Do đó, con hậu i đặt tại vị trí (i,x[i]) và con hậu j đặt tại vị trí (j,x[j]) phải thỏamãn ràng buộc: i-x[i] ¹ j-x[j] và i+x[i] ¹ j+x[j] với mọi i¹j
Ta có thể viết riêng một hàm Ok để kiểm tra các ràng buộc đó Nhưng giảipháp tốt hơn là dùng thêm các mảng đánh dấu để mô tả rằng một đường chéo chính
và phụ đã có một con hậu khống chế Tức là khi ta đặc con hậu i ở vị trí (i,j), ta sẽđánh dấu đường chéo chính i-j và đường chéo phụ i+j
Như vậy về cấu trúc dữ liệu, ta dùng 4 mảng:
- Mảng x với ý nghĩa: x[i] là cột ta sẽ đặt con hậu thứ i
- Mảng cot với ý nghĩa: cot[j]=true nếu cột j đã có một con hậu được đặt,ngược lại thì cot[j]=false
- Mảng dcc với ý nghĩa: dcc[k]=true nếu đường chéo chính thứ k đã có mộtcon hậu được đặt, tức là ta đã đặt một con hậu tại vị trí (i,j) mà i-j=k; ngược lại thìdcc[k]=false
- Tương tự ta dùng mảng dcp với ý nghĩa: dcp[k]=true nếu đường chéo phụthứ k đã có một con hậu được đặt
cot: array[1 max] of Boolean;
dcp: array[2 2 * max] of Boolean;
dcc: array[1 - max max - 1] of Boolean;
f1,f2: Text;
procedure Init;
begin
Assign(f1, InputFile); Reset(f1);
Assign(f2, OutputFile); Rewrite(f2);
ReadLn(f1, n);
FillChar(cot, SizeOf(cot), false);
FillChar(dcp, SizeOf(dcp), false);
FillChar(dcc, SizeOf(dcc), false);
end;
procedure Print;
Trang 18if i=n then print else Try(i+1);
cot[j]:=false; dcc[i-j]:=false; dcp[i+j]:=false ;{phục hồi trạng thái cũ} end;
*Phân tích
đến thăm tại lần di chuyển thứ i Các điều kiện của x như sau:
1 x = (x1,x2,…xn)
2 xi lấy giá trị trong tập {1,2,…n}
3 Ràng buộc: xi ¹ xj với mọi i¹j và a[xi,xi+1]>0 với mọi i=1,2, n, coi xn+1=x1
n
i i i
- mảng x[i]: ghi lại hành trình
- Mảng a[i,j]: chi phí để đi từ thành phố i đến thành phố j
Trang 19- Mảng d[i]: đánh dấu thành phố đã đi thăm, d[i]=true nếu đã đi thăm thànhphố i
Mỗi phương án của bài toán người du lịch là một hoán vị của n thành phố Vìphương án là một chu trình nên ta có thể coi thành phố xuất phát là thành phố 1
A: array[1 max, 1 max] of Integer;
X, Best : array[1 max + 1] of Integer;