Tải bản đầy đủ (.docx) (19 trang)

Một số bài toán quy hoạch động về dãy con nhằm bồi dưỡng học sinh giỏi tin học 11

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (119.47 KB, 19 trang )

1. MỞ ĐẦU
1.1.

Lý do chọn đề tài

Một trong những tiêu chí để đánh giá chất lượng một trường THPT là tỷ
lệ đạt học sinh giỏi của trường so với mặt bằng chung của tỉnh, của cả nước.
Chúng ta biết rằng để có kết quả cao trong cơng tác bồi dưỡng HSG thì học sinh
khơng những phải nắm chắc các kiến thức mà cịn phải biết được các phương
pháp, thuật tốn để giải được các bài tốn khó, nâng cao.
Nội dung tin học lập trình lớp 11 là một nội dung mới lạ đối với đa số học
sinh với nhiều khái niệm, thuật ngữ, cấu trúc dữ liệu mà học sinh mới được tiếp
xúc lần đầu. Vì vậy ngơn ngữ lập trình địi hỏi học sinh phải làm quen với nhiều
kiểu dữ liệu, để giải các bài toán trong Tin học thì việc xác định thuật tốn để
giải các bài tốn là công việc hết sức quan trọng. Tuy nhiên, đối với học sinh
việc thiết kế thuật toán nhằm giải quyết tối ưu bài tốn cịn gặp nhiều khó khăn.
Qua thực tế công tác giảng dạy hơn 10 năm ở trường, qua học hỏi kinh
nghiệm từ đồng nghiệp và qua nhiều lần đứng đội tuyển tôi nhận thấy rằng trong
các đề thi HSG Tin học cấp tỉnh có một số bài tốn cần sử dụng kỹ thuật lập
trình cao. Tuy có nhiều cách để giải quyết nhưng với mỗi bài toán nâng cao đó
đều có giới hạn về thời gian cũng như bộ nhớ của chương trình nên nếu khơng
lựa chọn thuật toán hiệu quả học sinh dễ dàng mất điểm các Test. Và trong
những bài toán nâng cao như vậy thì việc lựa chọn một thuật tốn hiệu quả là vơ
cùng quan trọng. Vì vậy, tơi đã nghiên cứu một chun đề các bài tốn về dãy
con trong đó có sử dụng phương pháp quy hoạch động nhằm đem lại kết quả tối
ưu cho bài tốn và đề tài tơi chọn là: “Một số bài toán quy hoạch động về dãy
con nhằm bồi dưỡng học sinh giỏi Tin học lớp 11”.
1.2. Mục đích nghiên cứu
Nhằm giúp học sinh giỏi lựa chọn được thuật toán tối ưu nhất để giải và
cũng góp thêm vào ngân hàng lượng bài tập nhằm hỗ trợ thêm cho công tác bồi
dưỡng học sinh giỏi.


Đưa ra thuật toán để giải quyết các bài toán cơ bản về phương pháp quy
hoạch động, nâng cao khả năng tư duy sáng tạo cho học sinh, nâng cao chất
lượng học sinh giỏi. Nêu vấn đề, phân dạng các bài toán tin học có liên quan,
thực hiện ví dụ minh họa, đưa ra thuật tốn và viết Code chương trình tham khảo
cho mỗi bài tốn đó để học sinh quan sát qua đó nắm vững kiến thức về phương
pháp quy hoạch động. Cũng thông qua đề tài nhằm cung cấp thêm một phương
pháp tư duy, tiếp cận để giải các bài toán trong bồi dưỡng HSG cấp tỉnh.
1.3. Đối tượng nghiên cứu
- Môn Tin học lớp 11 ở trường THPT
- Học sinh khá, giỏi khối 11 trường PT Nguyễn Mộng Tuân
- Nghiên cứu lí luận về bài tập giải bài tốn bằng phương pháp quy hoạch
động trong dạy học bồi dưỡng học sinh giỏi.

1


1.4. Phương pháp nghiên cứu
- Hình thành ở học sinh kỹ năng phân tích, xử lý các vấn đề liên quan đến
các bài toán về quy hoạch động.
- Xây dựng qui trình giảng dạy với bài tập sử dụng phương pháp quy
hoạch động trong việc tích cực hóa hoạt động nhận thức cho học sinh.
- Đánh giá, so sánh kết quả của học sinh
Để trình bày sáng kiến kinh nghiệm này, tôi đã sử dụng phối kết hợp
nhiều phương pháp như: nghiên cứu tài liệu, sách, báo, thông qua mạng, tham
khảo ý kiến của cấp trên và đồng nghiệp, điều tra cơ bản, thực nghiệm so sánh,
phân tích kết quả thực nghiệm phù hợp với môn học thuộc lĩnh vực Tin học.
2. NỘI DUNG SÁNG KIẾN KINH NGHIỆM
2.1. Cơ sở lý luận của sáng kiến kinh nghiệm
Trong quá trình học tập, chúng ta gặp rất nhiều các bài tập về Tốn -Tin.
Khi nào thì chúng ta cần đến quy hoạch động? Khơng có một cơng thức nào cho

các bài tốn như vậy. Tuy nhiên, có một số tính chất của bài tốn mà có thể nghĩ
đến quy hoạch động. Dưới đây là hai tính chất nhấn mạnh nhất:
- Bài tốn có các bài tốn con gối nhau
- Bài tốn có cấu trúc con tối ưu.
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
tốn hồn chỉnh có thể áp dụng cho mọi bài tốn. Tuy nhiên, người ta đã tìm ra
một số thuật tốn chung như chia để trị, tham ăn, quay lui,... Các thuật tố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ế.
Trong bài viết này, tôi muốn đề cập với các bạn một thuật tốn khác, đó là thuật
tốn quy hoạch động.
Để giải một bài tốn ta chia bài tốn đó thành các bài tố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 tốn con, ta có được lời
giải bài tốn ban đầu. Trong q trình giải các bài tố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
tốn con nào đó ta chỉ cần tìm 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ễ. Khi giải bài tố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.

2


- 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.
Căn cứ vào việc lựa chọn đội tuyển dự thi học sinh giỏi của nhà trường,
để đội ngũ học sinh giỏi của trường PT Nguyễn Mộng Tuân ngày càng đạt kết
quả cao hơn. Giúp cho học sinh chuyên tin khối THPT thi đạt kết quả ngày càng

cao, tạo ra nguồn tài liệu tham khảo về thuật toán hỗ trợ cho giáo học sinh và
giáo viên dạy đội tuyển học sinh giỏi trong nhà trường.
2.2. Thực trạng vấn đề trước khi áp dụng sáng kiến kinh nghiệm
Trong quá trình bồi dưỡng học sinh giỏi Tin học lớp 11 có nhiều bài tốn
có thể sử dụng nhiều thuật toán giải khác nhau. Nhưng khi chưa áp dụng phương
pháp quy hoạch động thì các bài tốn đó khi Test khơng lấy được hết điểm.
Thuật tốn khơng tối ưu, q thời gian. Đây cũng là khó khăn đối với học sinh vì
các em chưa được làm quen nhiều với các bài tập thiết kế thuật toán bằng
phương pháp quy hoạch động.
Qua việc giảng dạy học sinh khá, giỏi ôn thi học sinh giỏi Tin 11, tôi nhận
thấy việc hệ thống các bài tập theo từng chuyên đề có sử dụng phương pháp quy
hoạch động để học sinh tham khảo và luyện đề là hết sức quan trọng và có tính
hiệu quả cao.
2.3. Giải pháp đã sử dụng để giải quyết vấn đề
2.3.1.Phương pháp quy hoạch động
a. Tư tưởng của phương pháp
Quy hoạch động (Dynamic Programming) là một phương pháp rất hiệu
quả để giải nhiều bài toán tin học, đặc biệt là những bài toán tối ưu, có một số bà
tốn sử dụng phương pháp quy hoạch động lại cho hiệu quả cao hơn hẳn so với
nhiều phương pháp khác. Số lượng các bài thi có thể áp dụng phương pháp quy
hoạch động để giải trong đề thi học sinh giỏi môn Tin học thường rất cao.
Trong các phương pháp để giải một bài toán lập trình thì quy hoạch động
là phương pháp giảm thời gian chạy của các thuật tốn thể hiện các tính chất của
bài toán con gối nhau và cấu trúc con tối ưu. Cấu trúc con tối ưu có nghĩa là các
lời giải tối ưu cho các bài tốn. Có thể giải một bài toán với cấu trúc con tối ưu
bằng một quy trình ba bước:
- Bước 1: Chia bài tốn thành các bài toán con nhỏ hơn.
- Bước 2: Giải các bài toán này bằng cách tối ưu bằng cách sử dụng đệ
quy theo quy trình ba bước này.
- Bước 3: Sử dụng các kết quả tối ưu để xây dựng một lời giải tối ưu cho

bài toán ban đầu.
Các bài toán con được giải bằng cách chia chúng thành các bài toán nhỏ
hơn và cứ tiếp tục như thế cho đến khi ta đến được trường hợp đơn giản dễ tìm
cho lời giải.
Một bài tốn có các bài tốn con trùng nhau nghĩa là một bài tốn con đó
được sử dụng để giải nhiều bài toán lớn hơn khác nhau. Ví dụ trong dãy
Fibonaci, F3=F1+F2 và F4=F2+F3 khi tính mỗi số đều phải tính F 2. Khi tính F5 thì
3


cần đến F3 và F4. Như vậy tính F5 có thể tính F2 hai lần hoặc nhiều hơn. Điều này
áp dụng mỗi khi có các bài tốn con gối nhau giúp cho bài toán được tối ưu và
thời gian chạy chương trình cũng nhanh hơn.
- Trong phương án quy hoạch động, nguyên lý chia để trị càng được thể
hiện rõ: Khi khơng biết phải giải quyết những bài tốn con nào, ta sẽ đi giải
quyết tồn bộ các bài tốn con và lưu trữ những lời giải hay đáp số của chúng
với mục đích sử dụng lại theo một sự phối hợp nào đó để giải quyết những bài
tốn tổng quát hơn.
- Quy hoạch động bắt đầu từ việc giải tất cả các bài toán nhỏ nhất (bài
toán cơ sở) để từ đó từng bước giải quyết nhưng bài tốn lớn hơn, cho tới khi
giải được bài toán lớn nhất (bài tốn ban đầu). Q trình từ bài tốn cơ sở tìm ra
lời giải bài tốn ban đầu phải qua hữu hạn bước. Các bước cài đặt một chương
trình sử dụng quy hoạch động:
+ Giải tất cả các bài toán cơ sở (thông thường rất dễ), lưu các lời giải vào
bảng phương án.
+ Dùng công thức truy hồi phối hợp những lời giải của các bài toán nhỏ
đã lưu trong bảng phương án để tìm lời giải của các bài toán lớn hơn rồi lưu
chúng vào bảng phương án. Cho tới khi bài tốn ban đầu tìm được lời giải.
+ Dựa vào bảng phương án, truy vét tìm ra nghiệm tối ưu.
+ Cho tới nay, vẫn chưa có một định lý nào cho biết một cách chính xác

những bài tốn nào có thể giải quyết hiệu quả bằng quy hoạch động. Tuy nhiên
để biết được bài tốn có thể giải bằng quy hoạch động hay khơng, ta có thể đặt
câu hỏi:
+ Liệu có thể nào lưu trữ được nghiệm các bài tốn con dưới một hình
thức nào đó để phối hợp tìm được nghiệm bài tốn lớn?
+ Nhìn chung thường các bài toán tối ưu được giải bằng phương pháp truy
hồi thường được giải bằng phương pháp quy hoạch động độ phức tạp thuật toán
nhỏ hơn.
b. Các bước thực hiện quy hoạch động
Các bước cơ bản để giải một bài toán tối ưu bằng quy hoạch động:
- Bước 1: Lập hệ thức:
Dựa vào nguyên lý tối ưu tìm cách chia q trình giải bài tốn thành từng
giai đoạn, sau đó tìm hệ thức biểu diễn tương quan quyết định của bước đang xử
lý với các bước đã xử lý trước đó. Hoặc tìm cách phân rã bài tốn thành các bài
tốn con tương tự có kích thước nhỏ hơn, tìm hệ thức nêu quan hệ giữa kết quả
bài tốn kích thước đã cho với các kết quả của bài toán con cùng kiểu có kích
thước nhỏ hơn nhằm sử dụng các hàm hoặc thủ tục đệ quy.
Cách xây dựng hàm:
Chia việc giải bài toán thành n giai đoạn, mỗi giai đoạn i có trạng thái ban
đầu là t(i) và chịu tác động đến d(i) sẽ biến trạng thái tiếp theo t(i+1) của giai
đoạn i+1 (i=1,2,...,n-1). Theo nguyên lý tối ưu của Bellman việc tối ưu giai đoạn
cuối cùng không làm ảnh hưởng đến kết quả của bài toán. Với trạng thái ban đầu
là t(n), sau khi làm giai đoạn n tốt nhất ta có trạng thái của n-1 là t(n-1) và tác
động điều khiển của giai đoạn n-1 là d(n-1). Sau khi tối ưu giai đoạn n-1 ta lại có
4


t(n-2) và có thể tối ưu giai đoạn n-2... cho đến khi các giai đoạn từ n giảm đến 1
được tối ưu thì coi như hồn thành bài tốn. Gọi i giá trị tối ưu của bài tốn tính
đến giai đoạn k là Fk, giá trị tối ưu của bài tốn tính riêng ở giai đoạn k là Gk thì

Fk=Fk-1+Gk hay ta có cơng thức sau:
Fk(t(k))=max{Gk(t(k),d(k))+Fk-1(t(k-1))}(*)

- Bước 2: Tổ chức dữ liệu và chương trình
Các giá trị của Fk thường được lưu trữ trong một bảng (mảng một chiều
hoặc mảng hai chiều). Cần lưu ý khi khởi tạo giá trị ban đàu của bảng cho thích
hợp, đó là các kết quả của bài tốn con có kích thước nhỏ nhất của bài toán đang
giải
Fk(t(1))=max{Gt(t(1),d(1))+F0(t(0))}
Dựa vào hệ thức (*) và các giá trị đã có trong bảng để tìm dần các giá trị
cịn lại của bảng. Ngồi ra, cần mảng lưu trữ nghiệm tương ứng với giá trị tối ưu
trong từng giai đoạn.
- Bước 3: Truy vét, tìm nghiệm của bài toán dựa vào bảng phương án
Dựa vào bảng lưu trữ nghiệm và bảng giá trị tối ưu từng giai đoạn đã xây
dựng tìm ra kết quả bài tốn. Làm tốt thuật toán bằng cách thu gọn hệ thức (*)
và giảm kích thước miền nhớ. Thường tìm cách dùng mảng một chiều thay cho
mảng hai chiều nếu giá trị một dòng (hoặc cột) của mảng hai chiều chỉ phụ
thuộc một dòng (hoặc cột) kề trước.
2.3.2. Các bài toán quy hoạch động về dãy con
a. Bài toán 1: Dãy con tăng dài nhất liên tiếp
Cho dãy gồm N số nguyên a[1],a[2],...,a[n]. Một dãy được gọi là dãy con
của N gồm K phần tử liên tiếp là dãy: a[i],a[i+1],a[i+2],...,a[i+k-1].
Hãy tìm dãy con tăng liên tiếp dài nhất.
Dữ liệu vào: tệp văn bản BAI1.INP có cấu trúc như sau:
+ Dịng 1 chứa số ngun N (N<=1000)
+ Dòng thứ hai ghi N số nguyên là các số hạng trong dãy có giá trị tuyệt
đối <=1000, mỗi số cách nhau một dấu cách.
Dữ liệu ra: ghi ra tệp BAI1.OUT là dãy con tăng liên tiếp dài nhất của
dãy.
Ví dụ:

BAI1.INP
BAI1.OUT
7
3579
1243579
Phân tích thuật tốn:
Ta xây dựng bảng phương án F: Với F[j] là độ dài dãy tăng dài nhất từ a[i] bắt
đầu của dãy tăng tính tới phần tử a[j].
5


-

Khi đó F[0]
F[1]=1;
F[2]=1 Nếu a[2]F[2]=2=F[1]+1 nếu a[2]>=a[1]
F[3]=1 nếu a[3]F[3]=3=F[2]+1 nếu a[3]>=a[2]
…….
Như vậy: F[i]=1 nếu a[i]F[i]=F[i-1]+1 nếu a[i]>=a[i-1]
- Tại mỗi F[i] ta ghi nhận Dmax độ dài lớn nhất, và Dmax cuối cùng sẽ là
kết quả bài toán
Code Pascal tham khảo:
Procedure Res;
Var F:array[0..Nmax] of longint;
i,Dmax:longint;
Begin
F[1]:=1;Dmax:=1;

for i:=2 to n do
begin
if a[i]>a[i-1] then F[i]:=f[i-1]+1
Else
F[i]:=1;
Dmax:=max(Dmax,F[i]);
end;
if Dmax=1 then write(-1)
else
write(Dmax);
End;
b. Bài toán 2: Dãy con đơn điệu tăng
Cho một dãy số nguyên gồm N phần tử a1, a2, a3, …,aN.
Biết rằng dãy con tăng đơn điệu là 1 dãy a[i1], a[i2], …, a[ik] thỏa mãn:
+ i1< i2 < ik
+ a[i1]Yêu cầu: Hãy cho biết dãy con tăng đơn điệu dài nhất của dãy này có bao
nhiêu phần tử?
Dữ liệu: Vào từ file văn bản BAI2.INP
- Dòng 1: Chứa số n (0- Dòng 2: Chứa n số a1, a2, …,aN đôi một khác nhau và cách nhau ít nhất
một dấu cách ( |ai|≤10000)
Kết quả: Ghi ra file văn bản BAI2.OUT gồm một dòng ghi độ dài dãy
con tăng đơn điệu dài nhất
Ví dụ:
BAI2.INP
BAI2.OUT
10
6
3456822198

Phân tích thuật toán:
6


- Gọi L(i) là độ dài dãy con tăng dài nhất, các phần tử lấy trong miền từ a 1
đến ai và phần tử cuối cùng là ai. Dãy con đơn điệu tăng dài nhất kết thúc tai ai sẽ
được thành lập bằng cách:
- Kiểm tra xem có bao nhiêu dãy con đơn điệu tăng (các phần tử trong
miền từ a1 đến ai-1) mà ta có thể ghép ai vào cuối dãy đó.
- Chọn dãy con đơn điệu có độ dài lớn nhất để ghép ai vào.
Ta có cơng thức quy hoạch động để tính L(i) như sau:
• L(1) = 1.
• L(i) = max(1, L(j)+1 với mọi phần tử j: 0 < j < i và aj < ai)
Tính L(i) : phần tử đang được xét là a i .Ta tìm đến phần tử aj < ai có L(j)
lớn nhất. Khi đó nếu bổ sung ai vào sau dãy con a1...aj ta sẽ được dãy con tăng
dần dài nhất xét từ a1...ai.
* Xây dựng bảng phương án:
- Xét mảng A cho trước và mảng L là mảng lưu lại độ dài tốt nhất tại thời
điểm ta xét.
- Tại thời điểm đầu tiên, khi mảng A có 1 phần tử thì độ dài tốt nhất lưu lại
tại thời điểm xét đó là max=1
- Xét chạy đến phần tử kế tiếp theo nếu các giá trị trước đó nhỏ hơn số
đang xét thì độ dài lớn nhất của chuỗi=max+1
- Cịn khi xét chạy từ phần tử đầu đến phần tử đang xét khơng có giá trị
nào nhỏ hơn phần tử xét thì max:=0+1
Minh họa ví dụ trên qua lập bảng phương án như sau:
n=10
i
0
1

2
3
4
5
A[i] 3
4
5
6
8
2
L
1
2
3
4
5
1
L=6 là độ dài dãy con tăng đơn điệu dài nhất.

6
2
1

7
1
1

8
9
6


9
8
6

Code Pascal tham khảo:
Const fi=’BAI2.INP’;
fo=’BAI2.OUT’;
var a,f:array[1..1000] of integer;
h, i,j,n,max:integer; tg,cs:string;
BEGIN
assign(input,fi);reset(input);
assign(output,fo');rewrite(output);
readln(fi,n);
for i:=1 to n do read(fi,a[i]);
f[1]:=1;
for i:=2 to n do
begin
f[i]:=1;
for j:=1 to i-1 do
7


if (a[i]>a[j]) and (f[i]if maxend;
writeln(output,max);
close(input);close(output);
END.
c. Bài tốn 3: Dãy con tăng dài nhất khơng liên tiếp

Cho dãy số nguyên A1,A2,…,An. Hãy tìm một dãy con đơn điệu tăng của
dãy A có độ dài lớn nhất. (N<=10000).
Dữ liệu vào từ tệp văn bản BAI3.INP có cấu túc như sau:
+ Dòng 1: chứa số nguyên N.
+ Dòng 2: ghi N số nguyên là các số trong dãy số, mỗi số cách nhau một
dấu cách
Dữ liệu ra: tệp văn bản BAI3.OUT là một dãy con đơn điệu tăng của dãy
có độ dài lớn nhất (dãy con khơng liên tiếp tăng dài nhất).
Ví dụ:

BAI3.INP

BAI3.OUT

12

3 4 7 9 10

6 12 8 11 3 4 1 7 5 9 10 2
Phân tích thuật toán:
- Dùng mảng L[i] để lưu độ dài dãy con đơn điệu tăng dài nhất có các
phần tử từ 1 đến a[i]
- L[i] = 1 nếu không tồn tại j = 1 .. i-1 để a[j] < a[i]
- L[i] = max { L[i], j = 1..i-1 thỏa mãn a[j] < a[i]} + 1
Code Pascal tham khảo:

Cài đặt: dùng mảng T[i] để lưu vết
8



for i:=1 to n do T[i] := i;
L[1] := 1;
for i:=1 to n do
L[i] := 1;
For j := 1 to i - 1 do
if (a[i] >= a[j]) then
if (L[j] + 1 > L[i]) then begin L[i] := L[j] + 1; T[i] := j; end;
kq:=0;
for i:=1 to n do
if L[i] > kq then begin kq := L[i]; luu := i; end;
dem := 0;
while(T[luu] <> luu) do
begin inc(dem); k[dem] := luu; luu := T[luu] end;
inc(dem); k[dem] := luu;
// in ket qua
writeln(kq);
for i := dem downto 1 do write(k[i]:5);

Bài tốn 4: Tìm độ dài dãy đan dấu không liên tiếp dài nhất, với dạng bài
xuất dãy đan dấu dài nhất.
Phân tích thuật tốn:
- Trước hết ta hiểu dãy đan dấu là dãy không có hai phần tử cạnh nhau có
dấu giống nhau.
- Sử dụng phương pháp quy hoạch động.
- Gọi F[i-1] là độ dài dãy con đan dấu dài nhất xét ở phần tử A[i-1]
- Khi xét tới A[i] để F[i] lớn nhất khi đó sẽ chọn ra F[j] với j=(1..i-1) lớn
nhất có thể ghép được với A[i] hay chọn ra Max(F[j]) để ghép thêm A[i] vào với
A[j] để tạo dãy đan dấu dài nhất.
9



A[i] được xác định như sau:
• A[i]=1 nếu nó khơng ghép được với A[j]
• A[i]=1+Max(A[j]) Với j=(1..i-1)
Code Pascal tham khảo:
Procedure Res;
Var i,j,dmax:longint;
Begin
F[1]:=1;Dmax:=1;
For i:=2 to n do
begin
f[i]:=1;
for j:=1 to i-1 do
if (a[i]*a[j]<0) then
begin
f[i]:=max(f[i],f[j]+1);
Dmax:=max(dmax,F[i]);
end;
If dmax=1 then write(-1)
else
Write(dmax);
End;
e. Bài toán 5: Dãy con liên tiếp dài nhất có tổng bằng 0
Cho dãy A gồm N số nguyên a1a2……an. (N<100000). Hãy in ra dãy con
liên tiếp dài nhất trong dãy cho trước mà có tổng =0. (│ai│<109).
Ví dụ:
BAI5.INP
5
2 1 -2 3 -2


BAI5.OUT
1 -2 3 -2

Phân tích thuật tốn:
Phương pháp QHĐ ( Độ dài dãy con dài nhất)
• F[i] là tổng các phần tử từ a[1] tới a[i]
• Tìm các F[i]=0 => dạy có độ dài là d=i
• Tìm các cặp F[i]=F[j] => dãy có độ dài là d=j-i+1
=> Tìm Max(các d) là là độ dài dãy con dài nhất
Code Pascal tham khảo:
Procedure Res;
Var dmax,i,j:longint;
Begin
f[1]:=a[1];
For i:=2 to n do f[i]:=f[i-1]+a[i];
Dmax:=0;
For i:=1 to n do
10


begin
if f[i]=0 then dmax:=max(dmax,i);
for j:=i+1 to n do
if f[i]=f[j] then dmax:=max(dmax,j-i+1);
end;
If dmax=0 then write(-1)
else
write(dmax);
End;
f. Bài toán 6: Dãy con liên tiếp dài nhất có tổng chia hết cho K

Cho một dãy gồm n ( n ≤ 1000) số nguyên dương a 1,a2,..., an và số nguyên
dương k (k ≤ 50). Hãy tìm dãy con gồm nhiều phần tử nhất của dãy đã cho sao
cho tổng các phần tử của dãy con này chia hết cho k.
Dữ liệu vào: file văn bản BAI6.INP


Dịng đầu tiên chứa hai số n, k ghi cách nhau bởi ít nhất 1 dấu trống.



Các dịng tiếp theo chứa các số a1,a2,...,an được ghi theo đúng thứ tự cách
nhau ít nhất một dấu trống hoặc xuống dịng.

Kết quả: ghi ra file văn bản BAI6.OUT


Dịng đầu tiên ghi m là số phần tử của dãy con tìm được.



Các dòng tiếp theo ghi dãy m chỉ số các phần tử, giá trị của dãy đã cho có
mặt trong dãy con tìm được. Các chỉ số ghi cách nhau ít nhất một dấu
trắng hoặc một dấu xuống dịng.

Ví dụ :
BAI6.INP

BAI6.OUT

65


Do dai cac so chia het cho k: 4

11 6 7 12 20 8

Vi tri cac so chia het cho k: 1 2 5 6
Gia tri cac so chia het cho k: 11 6 20
8

Phân tích thuật tốn:
Phương pháp QHĐ ( Độ dài dãy con dài nhất)
• F[i] là số dư tổng các phần tử từ a[1] tới a[i] chia cho K
11





Tìm các F[i]=0 => dãy có độ dài là d=i
Tìm các cặp F[i]=F[j] => dãy có độ dài là d=j-i+1
=> Tìm Max(d) là là độ dài dãy con dài nhất

Code Pascal tham khảo:
Procedure Res;
var dmax,i,j:longint;
Begin
f[1]:=a[1] mod k;
For i:=2 to n do f[i]:=(f[i-1]+a[i]) mod k;
dmax:=0;
For i:=1 to n do

begin
if f[i]=0 then dmax:=max(dmax,i);
for j:=i+1 to n do
if f[i]=f[j] then dmax:=max(dmax,j-i+1);
end;
If dmax=0 then write(-1)
else
write(dmax);
End;
g. Bài toán 7: Dãy con đối xứng dài nhất
Cho dãy số a1,a2,…,an được gọi là đối xứng nếu các cặp số ở các vị trí i và
N-i+1 bằng nhau (với i=1…N). Cho trước một dãy số có N phần tử, mỗi phần tử
là số nguyên. Hãy tìm cách loại bỏ một số phần tử trong dãy để dãy thu được tạo
thành một dãy đối xứng dài nhất.
Dữ liệu vào: tệp văn bản BAI7.INP có cấu trúc như sau:
+ Dịng 1: chứa số nguyên N (2≤N≤5000)
+ Dòng thứ hai ghi N số nguyên là các số hạng trong dãy có giá trị tuyệt
đối ≤1000, mỗi số cách nhau một dấu cách.
Dữ liệu ra:tệp văn bản BAI7.OUT có cấu trúc như sau:
+ Dòng đầu ghi số nguyên M là số các số hạng của dãy đối xứng tìm được
+ Dịng thứ hai ghi M số hạng của dãy tìm được, mỗi số cách nhau một dấu
cách.
Ví dụ:
BAI7.INP
BAI7.OUT
13
7
1323152341432
2341432
Phân tích tḥt tốn:

- Áp dụng thuật toán quy hoạch động:
Gọi F[i,j] (i=1..N,j..N) là độ dài lớn nhất của dãy tìm được khi chọn các
phần tử của A từ phần tử thứ i đến j. Ta cần tìm F[1,N]
- Cơng thức quy hoạch động:
F[i,j]=0 với mọi i>j
F[i,j]=1 với i=j
Nếu A[i]=A[j] thì F[i,j]=F[i+1,j-1]+2
12


ngược lại F[i,j]=max{F[i,j-1],F[i+1,j]}.
- Sử dụng mảng hai chiều F[1..N,1..N] (2≤N≤5000)
- Điền các phần tử của mảng nằm trên đường chéo chính k= -1 đến 1-N với
điều kiện: Nếu F[i]=F[j] thì F[i,j]=F[i+1,j-1]+2, ngược lại F[i,j]=max(F[I,j1],F[i+1,j]);
Kết quả của bài toán là F[1,N]
Dựa vào mảng F ta xét lần ngược từ giá trị F[1,N] để lấy dãy các phần tử
tìm được.
Code Pascal tham khảo:
Const fi=’BAI7.INP’;
fo=’BAI7.OUT’;
nmax=5000;
var
a:array[1..nmax] of integer;
kt:array[1..nmax] of boolean;
F:array[1..nmax,1..nmax] of integer;
n:integer;
Procedure
inputdata;
Var i:integer;
Begin

assign(input,fi);reset(input);
assign(output,fo);rewrite(output);
readln(n);
for i:=1 to n do read(a[i]);
fillchar(kt,sizeof(kt,false));
fillchar(F,sizeof(F),0);
for i:=1 to n do F[i,i]:=1;
end;
Function max(x,y:integer):integer;
begin
if x>y then exit (x) else exit(y);
end;
Procedure QHĐ;
var i,j,k:integer;
begin
k:=0;
repeat
dec(k);
for i:=1 to n do
begin
j:=i-k;
if a[i]=a[j] then F[i,j]:=F[i+1,j-1]+2
else F[i,j]:=max(F[i,j-1],F[i+1,j])
end;
until k:=1-n;
13


end;
Procedure trace;

var i,j:integer;
begin
i:=1;j:=n;
repeat
while F[i,j]=F[i+1,j] do inc(i);
while F[i,j]=F[i,j-1] do dec(j);
kt[i]:=true; kt[j]:=true;
inc(i);dec(j);
until i>j
end;
Procedure outputdata;
var i,j:integer;
begin
assign(output,fo); rewrite(output);
writeln(F[1,n]);
for i:=1 to n do
if kt[i] then write(a[i],’ ’);
close(output);
end;
BEGIN
inputdata;
QHĐ;
trace;
outputdata;
END.
h. Bài tốn 8: Dãy con chung có độ dài lớn nhất của hai dãy
Cho hai dãy số nguyên (a1,a2,…,am), (b1,b2,…,bn). Tìm dãy con chung có độ
dài lớn nhất của hai dãy trên (coi dãy khơng có số ngun nào là dãy con của
mọi dãy và có độ dài bằng 0).
Ví dụ:

BAI8.INP

BAI8.OUT

132567
192563

1256

Phân tích thuật tốn:
- Chúng ta có thể thấy rằng độ phức tạp của bài toán trên phụ thuộc vào hai
số m, n. Xét hai trường hợp:
+ Trường hợp 1: m=0 hoặc n=0. Đây là trường hợp đặc biệt, có duy nhất
một dãy con chung của hai dãy có độ dài = 0. Vì vậy, dãy con chung có độ dài
lớn nhất của chúng có độ dài =0.
14


+ Trường hợp 2: m≠0 và n≠0.
Ở đây ta sử dụng phương pháp tối ưu là quy hoạch động, xét các bài tốn nhỏ
hơn là tìm dãy con chung có độ dài lớn nhất của hai dãy (a1,…,ai),(b1,…,bj). Như
vậy, ta phải tính tất cả các F[i,j], trong đó 0≤i≤m, 0≤j≤n. Gọi [i,j] là độ dài của
dãy con chung lớn nhất của hai dãy (a1,…,ai),(b1,…,bj). Như vậy ta phải tính tất
cả các F[i,j], trong đó 0≤i≤m, 0≤j≤n
- Thấy rằng F[0,0]=0
- Nếu ai≠bj thì F[i,j]=max{F[i-1,j],F[I,j-1]}
- Nếu ai=bj thì F[i,j]=1+F[i-1,j-1].
Như vậy, ta hồn tồn có thể tính được F[m,n] chính là độ dài của dãy con chung
dài nhất của (a1,…,am),(b1,…,bn).
Để tìm phần tử của dãy con, ta xuất phát từ ô F[m,n] tới ô F[0,0]. Giả sử ta đang

ở ô F[i,j].
- Nếu ai=bj thì ta thêm ai vào dãy con rồi nhảy tới ô F[i-1,j-1].
- Nếu ai≠bj thì F[i,j]=F[i-1,j] hoặc F[i,j]=F[i,j-1].
- Nếu F[i,j]=F[i-1,j] thì nhảy tới ơ F[i-1,j], ngược lại thì nhảy tới ô F[i.j-1].
Code Pascal tham khảo:
const
fi=’BAI8.INP’;
fo=’BAI8.OUT’;
var
a:array[1..10]of integer;
b:array[1..10] of integer;
kq:array[0..10,0..10] of integer;
i,j,maxa,maxb:integer;
f:text;
procedure init;
begin
assign(f,fi);reset(f);
i:=0;
while not(eoln(f)) do
begin
inc(i);
read(f.a[i]);
end;
maxa:=i;
readln(f);
i:=0;
while not (eoln(f)) do
begin
inc(i);
read(f.b[i]);

end;
maxb:=i;
close(f);
15


end;
function max(a,b:integer):integer;
begin
if a>b then max:=a
else max:=b;
end;
BEGIN
init;
kq[0,0]:=0;
for i:=1 to maxa do
for j:=1 to maxb do
if a[i] <> b[j] then kq[i,j]:=max(kq[i-1,j],kq[i,j-1]
else kq[i,j]:=kq[i-1,j-1]+1;
writeln(‘do dai day con chung lon nhat: ’,kq[maxa,maxb]);
i:=maxa;
j:=maxb;
while (i>0) or (j>0) do
if a[i]=b[j] then
begin
write(a[i]);
dec(i);
dec(j);
end
else

if kq[i-1,j]=kq[i,j] then dec(i);
else dec(j);
END.
2.4. Hiệu quả của sáng kiến kinh nghiệm đối với hoạt động giáo dục, với
bản thân, đồng nghiệp và nhà trường
a. Kết quả đạt được
Sau một thời gian nghiên cứu và hoàn thiện đề tài một số bài toán quy
hoạch động về dãy con đã đưa ra những thuật toán tối ưu và hiệu quả của nó
trong cơng tác bồi dưỡng HSG.
Về mặt lý thuyết, đề tài đã trình bày được cơ sở của quy hoạch động: khái
niệm, các bước giải bài toán quy hoạch động, cách nhận dạng bài tốn có áp
dụng phương pháp quy hoạch động hay không. Về mặt thực tiễn, đề tài đã giới
thiệu về một số bài toán quy hoạch động về dãy con để áp dụng trong việc giảng
dạy cho học sinh khá, giỏi THPT nhằm giúp cho kết quả thi HSG môn Tin học
tại trường ngày càng cao.
16


Với sáng kiến kinh nghiệm này, theo tôi cũng đã đóng góp một phần nhỏ
vào cơng tác bồi dưỡng HSG môn Tin học tại đơn vị tôi công tác – Trường PT
Nguyễn Mộng Tuân. Cũng góp phần trang bị thêm kiến thức cho các em học
sinh trong đội tuyển Tin học để các em có sự động lực, trang bị thêm cho mình
kiến thức để đạt được kết quả tốt nhất. Và đề tài cũng góp một phần giúp đồng
nghiệp có thêm tài liệu tham khảo, cùng nhau tự học và tự bồi dưỡng nâng cao
trình độ chun mơn của mình.
b. Kết quả thăm dị ý kiến học sinh
Đánh giá định tính
Sử dụng phương pháp quy hoạch động tạo được hứng thú cho học sinh.
Học sinh đã nâng cao được tính tư duy sáng tạo, vận dụng linh hoạt lập trình tốt
về các dạng bài tốn ứng dụng phương pháp quy hoạch động vào các bài tốn tối

ưu có bản chất đệ quy, tức là việc tìm phương án tối ưu cho bài tốn đó có thể
đưa về tìm phương án tối ưu của một số hữu hạn các bài toán con. Thời gian cho
học sinh thiết kế bài toán giảm thiểu, tạo hứng thú và khơi dậy lòng yêu thích
học lập trình, nhận thức và tư duy tốn lơgic, tư duy toán học tăng rõ rệt.
Đánh giá định lượng
Việc áp dụng phương pháp quy hoạch động vào giải các bài tốn về dãy
con nói chung và các chun đề bài tốn Tin học nói riêng khác tơi thấy rất hiệu
quả. Và công tác bồi dưỡng đội tuyển thi học sinh giỏi Tin học cấp tỉnh của tôi
trong những năm gần đây đã thu được một số kết quả như sau:
- Năm học 2015 - 2016: có 1 học sinh đạt giải khuyến khích cấp tỉnh
- Năm học 2017 - 2018: có 1 học sinh đạt giải khuyến khích cấp tỉnh
- Năm học 2020 - 2021: có 1 học sinh đạt giải khuyến khích cấp tỉnh.
3. Kết luận, kiến nghị
3.1. Kết luận
Với kết quả thực hiện qua các năm học như trên, tơi nhận thấy học sinh có
nhiều tiến bộ trong việc giải bài toán tin học. Nhiều em học sinh hồn thành tốt
u cầu của tơi đặt ra, đặc biệt là các em rất chú ý, hứng thú và nghiêm túc trong
giờ học. Điều này đã tạo cho tôi niềm tin, sự phấn khởi để tơi có thể tiếp tục áp
dụng kết quả đạt được cho những năm học sau.
Hệ thống lý thuyết và một số bài tập quy hoạch động về dãy con được đưa
ra để học sinh có thể luyện tập và nâng cao kỹ năng lập trình của mình, hơn nữa
các bài tốn được phân loại và tập hợp thành hệ thống bài tập chuyên đề cụ thể.
Điều này gây hứng thú hơn cho học sinh trong quá trình nghiên cứu và vận
dụng. Tuy nhiên, do thời gian có hạn nên trong đề tài này cũng mới đưa ra được
một chuyên đề các bài toán về dãy con có sử dụng phương pháp quy hoạch
động.
Thơng qua việc xây dựng một số bài toán tối ưu giải bằng phương pháp
quy hoạch động, các em đã từng bước hình thành kỹ năng cơ bản trong lập trình
và thực hiện việc thiết kế bài toán tối ưu một cách thành thạo hơn, làm tiền đề để
học sinh lập trình tốt các ngơn ngữ lập trình nâng cao khác.Trong q trình thực

17


hành và làm bài tập cũng tạo cho học sinh tinh thần trách nhiệm, nhận thức đúng
đắn về môn học, khơi dậy lịng say mê mơn học và tạo hứng thú học tập cho học
sinh. Việc thiết kế các bài toán tối ưu bằng phương pháp quy hoạch động đã
nâng cao được tính tư duy sáng tạo, vận dụng linh hoạt lập trình tốt về các dạng
bài tốn ứng dụng các bài toán cơ bản chất đệ quy, giúp học sinh giải quyết được
rất nhiều bài toán liên quan.
Với thời gian công tác chưa lâu, và nội dung nghiên cứu cịn hạn chế
nhưng tơi cũng đã cố gắng tìm ra những bài tốn về chun đề dãy con có sử
dụng phương pháp quy hoạch động, nhằm giúp cho công tác ôn thi HSG Tin học
thu được kết quả cao hơn.Thời gian viết đề tài hạn chế, mặc dù bản thân đã cố
gắng nhiều nhưng trong đề tài không thể không có những thiếu sót. Kính mong
các đồng nghiệp và q các thầy cơ giáo tham gia góp ý, chỉnh sửa và hoàn
thiện đề tài này hơn nhằm đem lại hiệu quả trong giảng dạy và học tập của học
sinh.
3.2. Kiến nghị
Tôi mong rằng nhà trường cần tạo điều kiện hơn nữa về mặt thời gian, tài
liệu cho giáo viên và học sinh bồi dưỡng thêm kiến thức. Thư viện cần bổ sung
thêm tài liệu tham khảo, bồi dưỡng về môn tin học đặc biệt đối với bộ môn đặc
thù này thì việc trang bị cơ sở vật chất phịng học, phòng máy thực hành đảm
bảo tốt là rất quan trọng. Và trong năm học tới những giải pháp này vẫn được
Ban giám hiệu quan tâm chỉ đạo, giúp đỡ để giáo viên có điều kiện trao đổi, học
hỏi kinh nghiệm và phát huy được năng lực của mình khơng những tạo ra được
sự hứng thú cho học sinh mà còn thu được kết quả cao.
Qua đây, tơi cũng kính mong lãnh đạo cấp trên thường xuyên mở các lớp
tập huấn quản lý thiết bị CNTT, các phần mềm ứng dụng trong học tập đến tất
cả các giáo viên có sử dụng thiết bị CNTT trong trường học. Và nên tổ chức các
hội thảo, chuyên đề trong công tác bồi dưỡng học sinh giỏi để nhân rộng kinh

nghiệm và tạo điều kiện cho các trường học hỏi.
Trên đây là hệ thống một số chuyên đề các bài toán về dãy con có sử dụng
phương pháp quy hoạch động mà tơi đã đúc rút và áp dụng có hiệu quả trong
việc ơn thi học sinh giỏi Tin THPT lớp 11 ở trường PT Nguyễn Mộng Tuân. Tôi
hy vọng sẽ phần nào bổ sung các kiến thức, giúp các đồng nghiệp tham
khảo.Tuy nhiên, đề tài này khơng thể tránh khỏi những thiếu sót, rất mong được
sự góp ý chân thành của các đồng nghiệp, của Ban giám hiệu, đặc biệt là của hội
đồng sáng kiến kinh nghiệm để đề tài được hoàn chỉnh hơn. Tơi xin chân thành
cảm ơn.

XÁC NHẬN CỦA

Thanh hóa, ngày 10 tháng 05 năm 2021
18


THỦ TRƯỞNG ĐƠN VỊ

Tôi xin cam đoan đây là SKKN của bản
thân viết, không sao chép nội dung của
người khác.
Người viết đề tài

Lê Thị Thanh Huyền

19




×