You are on page 1of 20

CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM

Độc lập – Tự do – Hạnh phúc



SÁNG KIẾN KINH NGHIỆM:

MỘT SỐ PHƯƠNG PHÁP TIẾP CẬN BÀI TOÁN,


LÀM GIẢM ĐỘ PHỨC TẠP CỦA THUẬT TOÁN

-1-
Quảng Bình, tháng 12 năm 2018
MỤC LỤC

MỤC LỤC......................................................................................................2
I. MỞ ĐẦU........................................................................................................3
1. Lý do chọn đề tài ....................................................................................3
2. Điểm mới của đề tài.................................................................................3
3. Phạm vi áp dụng đề tài...........................................................................3
II. NỘI DUNG....................................................................................................4
1. Thực trạng vấn đề cần nghiên cứu...........................................................4
2. Biện pháp tiến hành.................................................................................4
Dạng 1: Một số bài toán duyệt cơ bản...............................................................5
Bài 1: Sắp xếp..............................................................................................5
Bài 2: Tích lớn nhất......................................................................................6
Bài 3: Tổng 2 số lớn.....................................................................................9
Dạng 2: Sử dụng thuật toán chia để trị để giảm độ phức tạp của bài toán.......14
Bài 1: Chọn dãy số....................................................................................14
Bài 2: Hieu................................................................................................16
3. Đánh giá kết quả thực nghiệm...............................................................18
III. KẾT LUẬN..................................................................................................19
IV. TÀI LIỆU THAM KHẢO..........................................................................20

-2-
I. PHẦN MỞ ĐẦU
1. Lý do chọn đề tài
Bài toán trong tin học là bài toán xuất phát từ bài toán thực tế, việc xây dựng
giải thuật để giải bài toán tin học bằng máy tính phải bảo đảm những tính chất
cơ bản của thuật toán, trong các tính chất chất cơ bản đó thì yêu cầu về thuật
toán sau khi đã được cài đặt chương trình trên máy tính bằng ngôn ngữ lập trình
thì thuật toán phải chạy nhanh, tốn ít thời gian và bộ nhớ. Đây là yêu cầu rất
quan trọng đối với những học sinh tham gia đội tuyển học sinh giỏi. Điều này
được thể hiện rất rõ trong nhiều bài toán qua các đề thi học sinh giỏi Tỉnh trong
những năm gần đây. Trong những bài toán này thường yêu cầu của nó được chia
thành nhiều mức nhằm mục đích phân loại được trình độ của học sinh. Mức độ
khó của bài toán phụ thuộc rất nhiều vào vào độ lớn của dữ liệu đầu vào nên
ngoài vấn đề về việc chọn được giải thuật để cho kết quả đúng đòi hỏi chương
trình phải chạy hết các bộ test lớn bằng một đơn vị thời gian đã được quy định
trong từng bài toán mới đạt được mức điểm tối đa. Để đảm bảo được yêu cầu đó,
đòi hỏi giải thuật để giải quyết bài toán phải có độ phức tạp tính toán càng nhỏ
càng tốt.
Khi tiếp cận với một bài toán, tùy theo trình độ của từng học sinh mà mỗi
học sinh có cách phân tích bài toán và lựa chọn thuật toán khác nhau để giải nó.
Đối với những học sinh có trình độ chưa cao, chưa có khả năng phân tích bài
toán tốt thường lựa chọn những thuật toán đơn giản, có độ phức tạp lớn đồng
nghĩa với số điểm nhận được thấp hơn. Để có kết quả tốt hơn, đòi hỏi học sinh
phải có trình độ cao hơn, kỹ năng phân tích bài toán tốt hơn để tìm ra những
thuật toán tốt có độ phức tạp tính toán nhỏ. Đây là vấn đề mà mỗi giáo viên tin
học tham gia bồi dưỡng đội tuyển học sinh giỏi luôn coi trọng. Đòi hỏi giáo viên
phải tìm ra những phương pháp phù hợp cho từng đối tượng học sinh để giúp
học sinh từng bước tiếp cận bài toán tin học từ đơn giản đến phức tạp hơn phù
hợp với năng lực của mình để dành được điểm số cao nhất có thể.
Với những lý do trên tôi chọn đề tài sáng kiến kinh nghiệm với nhan đề:
“Một số phương pháp tiếp cận bài toán, làm giảm độ phức tạp của thuật
toán”
2. Điểm mới của đề tài:
Tính mới của đề tài thể hiện việc thu thập một số bài toán sữ dụng trong
bồi dưỡng học sinh giỏi và một số đề thi cấp tỉnh từ đó phân loại các bài toán
theo các dạng, phân tích các dạng bài toán theo từng chủ đề dựa trên những
thuật toán cơ bản đến nâng cao để tìm cách xây dựng giải thuật tốt nhất cho việc
giải những dạng bài toán giống nhau và dạng tương tự.
3. Phạm vi áp dụng đề tài:
Đề tài được áp dụng trong bồi dưỡng HSG 11 năm học 2017-2018.

-3-
II. NỘI DUNG

1.Thực trạng vấn đề cần nghiên cứu:.


Trong quá trình bồi dưỡng học sinh gỏi vấn đề về phát triển kỹ năng cho
học sinh đòi hỏi người giáo viên phải thường xuyên tìm tòi phương pháp, phải
có những hệ thống bài tập từ đơn giản đến nâng cao để phát triển kỹ năng
thường xuyên cho học sinh mới đáp ứng yêu cầu ngày càng cao của bài toán
trong tin học.
Khi tiếp xúc với một bài toán trong tin học, học sinh thường cố gắng tìm
ra thuật toán tốt nhất để giải quyết trọn vẹn bài toán, đối với những bài toán đơn
giản học sinh có thể tìm ra ngay thuật toán nhưng đối với những bài toán khó
đặc biệt là những bài toán có dữ liệu đầu vào lớn thì việc tìm ra thuật toán tối ưu
nhất để đạt được số điểm tối đa thường là rất khó. Học sinh không nghĩ được
rằng nếu sử dụng những giải thuật đơn giản để giải quyết các bài toán khó thì
cho dù không đạt được số điểm tối đa nhưng cũng có được một điểm số ở một
mức độ nào đó phù hợp với khả năng của mình để tránh điểm không. Đây là và
kinh nghiệm cần thiết đối với những học sinh giỏi tham gia những ký thi HSG
môn tin học.
Trước khi áp dụng sáng kiến kinh nghiệm kết quả khảo sát cho các học
sinh giỏi khối 11 là:
- Mức điểm giỏi: 0%
- Mức điểm khá: 30%
- Mức điểm TB: 55%
- Mức điểm yếu: 15%
Để rèn luyện kỹ năng tiếp cận bài toán nhằm giúp học sinh có được kinh
nghiệm tiếp cận bài toán khó bằng nhiều thuật toán theo từng bước từ đơn giản
đến phức tạp phù hợp với khả năng của mình để có được điểm số tốt nhất đòi
hỏi người giáo viên cần rèn luyện kỹ năng tiếp cận bài toán để làm giảm độ
phức tạp của bài toán.
2. Biện pháp tiến hành
Để giải một bài toán tin học trên máy tính chúng ta thường phải thực hiện
theo từng bước:
Bước đầu tiên và là bước quan trọng nhất là hiểu rõ nội dung bài toán.
Đây là yêu cầu quen thuộc đối với những người làm toán. Để hiểu bài
toán theo cách tiếp cận của tin học ta phải gắng xây dựng một số ví dụ phản ánh
đúng các yêu cầu đề ra của đầu bài rồi thử giải các ví dụ đó để hình thành dần
những hướng đi của thuật toán.
Bước thứ hai là dùng một ngôn ngữ quen thuộc, tốt nhất là ngôn ngữ toán
học đặc tả các đối tượng cần xử lí ở mức độ trừu tượng, lập các tương quan, xây

-4-
dựng các hệ thức thể hiện các quan hệ giữa các đại lượng cần xử lí để có được
thuật toán tốt nhất có thể.
Bước thứ ba là xác định cấu trúc dữ liệu để biểu diễn các đối tượng cần
xử lí cho phù hợp với các thao tác của thuật toán.
Trong những bước tiếp theo ta tiếp tục làm mịn dần các đặc tả theo trình
tự từ trên xuống, từ trừu tượng đến cụ thể, từ đại thể đến chi tiết.
Bước cuối cùng là sử dụng ngôn ngữ lập trình đã chọn để viết chương
trình hoàn chỉnh. Ở bước này ta tiến hành theo kĩ thuật đi từ dưới lên, từ những
thao tác nhỏ đến các thao tác tổ hợp.
Sau khi nhận được chương trình ta cho chương trình chạy thử với các dữ
liệu lấy từ các ví dụ đã xây dựng ở bước đầu tiên.
Chúng ta sẽ vận dụng cách tiếp cận trên để giải một số bài toán cụ thể
trong đó chủ yếu là bước thứ hai để tìm thuật toán tốt nhất. Sau đây là một số
phương pháp cụ thể để tối ưu độ phức tạp tính toán của giải thuật.
Dạng 1: Một số bài toán duyệt cơ bản
Bài 1: Sắp xếp
Cho một dãy X gồm N số nguyên trong phạm vi từ -10000 đến 10000 (1
N 65000). Hãy sắp xếp dãy số này theo thứ tự giảm dần.
Dữ liệu vào cho trong file văn bản SORT.INP trong đó dòng đầu chứa số
N. Dòng thứ 2 chứa N số i trong dãy X, các số cách nhau một khoảng trắng.
Kết quả ghi ra file văn bản với tên SORT.OUT trong đó lần lượt ghi ra
các phần tử của dãy X đã được sắp xếp.
Ví dụ:
SORT.INP SORT.OUT
4 5433
3435

Lời giải:
+ Nếu sử dụng thuật toán sắp xếp thông thường như Quick Sort thì độ
phức tạp tính toán cũng chỉ là O(Nlog2N).
+ Đối với bài này, để thuật toán chạy nhanh hơn ta sử dụng phương pháp
sắp xếp đếm phân phối với độ phức tạp giảm tới là O(N) khi các số trong dãy là
đôi một khác nhau.
Gọi Di là số lần xuất hiện của số có giá trị bằng i trong dãy.
Như vậy mỗi lần đọc số có giá trị i trong dãy ta tăng Di lên 1 đơn vị
Đoạn chương trình sau sẽ đọc tất cả các số trong dãy để tạo mảng D chứa
tần suất xuất hiện của các số trong dãy số đã cho:
For i:=1 to N do
Begin
Read(x);

-5-
D[x]:=D[x]+1;
End;
Vấn đề còn lại là dựa vào mảng D để in ra các số trong dãy theo thứ tự
giảm dần. Đoạn chương trình sau in ra dãy số đã cho theo thứ tự giảm dần.

For i:=10000 downto -10000 do


If D[i]>0 then
For j:=1 to D[i] do writeln(i);

Chương trình:
Const fi='sort.inp';
fo='sort.out';
Var D: array[-10000..10000] of Word;
n, i: longint;
f, f1: text;
BEGIN
Assign(f,fi);
Reset(f);
Assign(f1,fo);
Rewrite(f1);
Fillchar(D,sizeof(D),0);
Readln(f,n);
For i:=1 to n do
Begin
Readln(f,x);
Inc(D[x]);
End;
For i:=10000 downto -10000 do
If D[i]>0 then
For j:=1 to D[i] do write(f1,i,' ');
Close(f);
Close(f1);
END.

Bài 2: Tích lớn nhất


Cho một dãy gồm N số nguyên. Hãy tìm 3 số trong dãy với tích T của
chúng là lớn nhất.
Dữ liệu: Vào từ file văn bản TICHMAX.INP:
- Dòng đầu ghi số N (3 N 10000).

-6-
- Dòng thứ hai chứa N số nguyên có giá trị tuyệt đối không vượt quá
1000.
Kết quả: Ghi ra file văn bản TICHMAX.OUT một số duy nhất T.

Ví dụ:
TICHMAX.INP TICHMAX.OUT
9 810
3 5 1 7 9 0 9 -3 10
Lời giải:
+ Cách tiếp cận tầm thường: Sử dụng thuật toán duyệt vét cạn với độ phức
tạp O(n3) như sau:
KQ:=MinInt;
For i:=1 to n-2 do
For j:=i+1 to n-1 do
For k:=1 to n do
If a[i]*a[j]*a[k] > KQ then KQ:=a[i]*a[j]*a[k];
+ Chúng ta có cách tiếp cận sau đây có thể đưa độ phức tạp của thuật toán
về O(n).
Nếu tích lớn nhất của 3 phần tử bao gồm:
- Ba số dương: Ba số này phải lần lượt là số lớn nhất, nhì, ba trong dãy.
- Một số âm và hai số dương: Dãy phải gồm đúng hai số dương, vì nếu
không ta có thể lấy tích ba số dương để đạt giá trị lớn hơn. Ta cũng suy ra ba số
này phải là ba số lớn nhất, nhì, ba trong dãy.
- Hai số âm và một số dương: Số dương phải là số lớn nhất và hai số âm
phải là hai số nhỏ nhất, nhì trong dãy.
- Ba số âm: Dãy phải gồm toàn số âm, vì nếu có một số dương ta cũng có
thể lấy tích của số dương đó và hai số âm để thu được tích dương. Ta cũng suy
ra được ba số cần tìm phải là ba số lớn nhất, nhì, ba của dãy.
Vậy suy ra, T=max(max1*max2*max3,min1*min2*max1), với max1,
max2, max3, min1, min2 lần lượt là số lớn nhất, nhì, ba và số nhỏ nhất, nhì của
dãy.
Ta có thể đọc qua lần lượt các số của dãy và cập nhật max1, max2, max3,
min1, min2 mà không cần lưu lại dãy số. Đoạn lệnh dưới đây cập nhật min1,
min2 khi đọc vào một số mới x:

If (x<=min1) then
Begin
min2:=min1; {min1 giờ trở thành số bé thứ hai}
min1:=x; {số bé nhất là x}
End

-7-
Else If (x<=min2) then min2:=x; {số bé thứ hai là x}

Việc cập nhật max1, max2, max3 được thực hiện hoàn toàn tương tự.

Chương trình
Program Tich;
Const fi='tichmax.inp';
fo='tichmax.out';
Var max1,max2,max3,min1,min2,x:integer;
i,n, kq:longint;
f, f1: Text;
Function max(a,b:longint):longint;
Begin
if a>b then max:=a
else max:=b;
End;
BEGIN
Assign(f,fi);
Reset(f);
Assign(f1,fo);
Rewrite(f1);
max1:=-1000; max2:=max1; max3:=max1;
min1:=-1000; min2:=min1;
Readln(F,n);
for i:=1 to n do
Begin
Read(f,x);
If (x>=max1) then
Begin
max3:=max2;
max2:=max1;
max1:=x;
End
Else
If (x>=max2) then
Begin
max3:=max2;
max2:=x;
End

-8-
Else if (x>=max3) then max3:=x;
If (x<=min1) then
Begin
min2:=min1;
min1:=x;
End
Else if (x<=min2) then min2:=x;
End;
kq:=max(max1*max2*max3,min1*min2*max1);
writeln(f1,kq);
close(f1);
close(f);
END.

Bài 3: Tổng 2 số lớn:


Cho số nguyên X có M chữ số, số nguyên Y có N chữ số
Yêu cầu:
Tính tổng của X và Y
Dữ liệu vào: Cho trong tệp SUM.INP với cấu trúc.
Dòng 1: Ghi hai số M, N (1<M,N<30000), hai số cách nhau một dấu cách
Dòng 2: Ghi số X
Dòng 3: Ghi số Y
Dữ liệu ra: Ghi ra tệp SUM.OUT với cấu trúc
Dòng 1: Ghi tổng của X và Y
Ví dụ:
SUM.INP SUM.OUT
3 4 1357
123
1234
Lời giải:
Sử dụng hai xâu để lưu trữ giá trị của hai số lớn.
Var so1, so2: String;
Chương trình:
Program CongSL;
Const fi='SUM.INP';
fo='SUM.OUT';
Var s1,s2,s3:String;
i , m,n:Integer;
Procedure Docdl;
Var f:text;

-9-
ch:char;
Begin
Assign(f,fi);
Reset(f);
Readln(f,m,n);
Readln(f,s1);
Readln(f,s2);
End;
Function Cong(a,b : String): String;
Var tong, nho, i, x, y,code : integer;
c, s : String;
Begin
nho:=0; c:='';
While length(a)<length(b) do
a:='0'+a;
While length(b)<length(a) do
b:='0'+b;
For i:=length(a) downto 1 do
Begin
Val(a[i],x,code);
Val(b[i],y,code);
tong:=x + y + nho;
nho:=tong div 10;
Str(tong mod 10,s);
c:=s+c;
End;
If nho>0 then c:='1'+c;
Cong:=c;
End;
Procedure Ghidl;
Var f: text;
Begin
Assign(f,fo); Rewrite(f);
S3:=cong(s1,s2);
Write(f,s3); Close(f);
End;
BEGIN
Docdl;
Ghidl;
END.

-10-
Với phương pháp này, chúng ta chỉ tính toán được với những con số có
không quá 255 chữ số. Vậy với bài toán khi những con số có đến 30000 chữ số
không thể giải quyết được. Thêm vào đó nếu số lượng chữ số là 255 thì số lượng
phép toán chuyển đổi từ ký tự thành số và ngược lại là rất nhiều, điều đó làm
tăng thời gian thực hiện của chương trình.
Cách tiếp cận sau đây sẽ giảm độ phức tạp của bài toán:
Chúng ta vẫn sử dụng mảng kiểu số để lưu trữ một số có nhiều chữ số.
Mảng có 3.500 phần tử mỗi phần tử kiểu longint. Mỗi phẩn tử của mảng lưu trữ
một số nguyên có 9 chữ số. Với phương pháp này ta đã tính toán được trên hai
số có 30.000 chữ số với thời gian nhanh nhất. Khi cộng (hoặc trừ) hai số có
30.000 chữ số, ta chỉ cần sử sụng 3.100 phép cộng (hoặc phép trừ) và việc cải
tiến thủ tục đọc dữ liệu sẽ giúp thuật toán hoàn toàn loại bỏ được các thao tác
chuyển đổi ký tự thành số

Chương trình:
Program CongSL;
Const fi='SUM.INP';
fo='SUM.OUT';
Var A,B: Array[0..3500] of longint;
i, m,n:Integer;
Procedure Docdl;
Var f:text;
s:String[9]; ch:char;
dua,dub,code:Integer;
Begin
Fillchar(A,sizeof(A),0);
Fillchar(B,sizeof(B),0);
Assign(f,fi);
Reset(f);
Readln(f,m,n);
dua:=m mod 9;
dub:=n mod 9;
m:=m div 9;
n:=n div 9;
If m>n then
Begin
s:='';
For i:=1 to dua do
Begin
read(f,ch);

-11-
s:=s+ch;
End;
Val(s,A[1],code);
For i:= 2 to m+1 do
Begin
Read(f,s);
Val(s,A[i],code);
End;
Readln(f);
s:='';
For i:=1 to dub do
Begin
read(f,ch);
s:=s+ch;
End;
Val(s,B[m-n+1],code);
For i:= m-n+2 to m+1 do
Begin
Read(f,s);
Val(s,B[i],code);
End;
End
Else
Begin
s:='';
For i:=1 to dua do
Begin
read(f,ch);
s:=s+ch;
End;
Val(s,A[n-m+1],code);
For i:= n-m+2 to n+1 do
Begin
Read(f,s);
Val(s,A[i],code);
End;
Readln(f);
s:='';
For i:=1 to dub do
Begin

-12-
read(f,ch);
s:=s+ch;
End;
Val(s,B[1],code);
For i:= 2 to n+1 do
Begin
Read(f,s);
Val(s,B[i],code);
End;
End;
Close(f);
End;
Procedure XL;
Begin
If m>n then n:=m;
For i :=n+1 downto 1 do
Begin
B[i]:=B[i]+A[i];
If B[i] div 1000000000 = 1 then
Begin
B[i]:=B[i] mod 1000000000;
inc(B[i-1]);
End;
End;
End;
Procedure Ghidl;
Var f:text;
Begin
Assign(f,fo);
Rewrite(f);
If B[1]<>0 then Write(f,B[1]);
For i:=2 to n+1 do
If B[i] =0 then Write(f,'000000000')
Else Write(f,B[i]);
Close(f);
End;
BEGIN
Docdl; Xl;
Ghidl;
END.

-13-
Dạng 2: Sử dụng thuật toán chia để trị để giảm độ phức tạp của bài toán
Bài 1: Chọn dãy số
Một lần, Cuội và Bờm đang chơi với nhau. Cuội vẽ lên đất một dãy gồm
N ô vuông liên tiếp nhau và viết vào mỗi ô một số nguyên dương. Cuội thách
Bờm hãy chọn một dãy các ô liên tiếp nhau sao cho tổng các số trong dãy các ô
đã chọn bằng tổng các số trong các ô còn lại.
Yêu cầu: Hãy tính xem Bờm có bao nhiêu cách chọn thỏa mãn yêu cầu
mà Cuội đã đưa ra?
Dữ liệu vào: Tệp văn bản CHONDAY.INP
+ Dòng đầu ghi số nguyên N (2<=N<=105)
+ Dòng thứ hai ghi N số nguyên cách nhau một dấu cách. Các số trên
dòng này không vượt quá 1000.
Dữ liệu ra: Tệp văn bản CHONDAY.OUT chỉ ghi duy nhất một số
nguyên là số cách mà Bờm có thể chọn.
Ví dụ:
CHONDAY.INP CHONDAY.OUT
4 2
4121

Lời giải:
Gọi A là dãy gồm N phần tử đã cho
Bài toán quy về đếm xem có bao nhiêu đoạn liên tục từ vị trí i đến j (1
i<j n) trong A có tổng các phần tử của nó này bằng nửa tổng tất cả các phần tử
trong dãy A.
Cách 1: Thuật toán tầm thường
Gọi T là tổng các số trong dãy. Nếu T lẻ bài toán có nghiệm bằng 0.
Ngược lại gán S = T div 2.
Sử dụng thuật toán duyệt kết hợp với việc lưu trữ tổng các số trên mảng
một chiều ta dễ dàng giải bài toán với độ phức tạp O(n2).
Gọi Bi là tổng các phần tử từ 1 đến i trong A (i=0..n và B 0=0). Như vậy
tổng các phần tử trong A từ i đến j (i j) = Bj – Bi-1.
Thuật toán tạo mảng B nhu sau:

B[0]:=0;
For i:=1 to n do B[i]:=A[i]+B[i-1];
Thuật toán duyệt sẽ như sau:
dem:=0;
For i:=1 to n do
For j:=i to n do
If B[j]-B[i-1] = S then Inc(dem);

-14-
Cách 2: Duyệt kết hợp tìm kiếm nhị phân để đưa độ phức tạp về O(nlgn)
Về cấu trúc dữ liệu tương tự cách 1. Ta để ý rằng vì B i là tổng các phần tử
dương trong A từ 1 đến i nên Bi > Bi-1 hay nói cách khác dãy các phần tử trong B
tăng dần.
Gọi j là phần tử cuối của dãy cần tìm phần tử i trước j sao cho B[j]-B[i-1]
bằng S. Để tìm i ta dùng thuật toán tìm kiếm nhị phân vì dãy B là dãy tăng dần.
Điều đó cho phép giảm độ phức tạp xuống còn O(nlgn)
Chương trình
Program Chondayso;
Const fi = 'CHONDAY.INP';
fo = 'CHONDAY.OUT';
maxn=100001;
Var A:array[0..maxn] of longint;
n,kq,t:longint;
Procedure Docdl;
Var f:text;
i, x:longint;
Begin
Fillchar(a,sizeof(a),0);
kq:=0;
Assign(f,fi); reset(f);
Readln(f,n);
For i:=1 to n do
Begin
Read(f,x);
a[i]:=a[i-1]+x;
End;
Close(f);
End;
Procedure Tim(d,c,v:longint);
Var m,sum:longint;
Begin
If d>c then exit;
m:=(d+c) div 2;
sum:=a[v]-a[m-1];
If sum = t then inc(kq)
Else
If sum < t then Tim(d,m-1,v) else Tim(m+1,c,v);
End;

-15-
Procedure Ghi;
Var f:text;
Begin
Assign(f,fo); Rewrite(f);
Writeln(f,kq);
Close(f);
End;
Procedure Xuli;
Var i:longint;
Begin
If odd(a[n]) then
Begin
kq:=0;
ghi;
exit;
End;
t:=a[n] div 2;
for i:=n downto 1 do Tim(1,i, i);
Ghi;
End;
BEGIN
Doc;
Xuli;
END.

Bài 2: Hiệu
Cho mảng số nguyên A[1..n], cần tìm Hieu(A[1..n]) = A[j]-A[i] đạt giá trị
lớn nhất mà (1 i j n).
Input: Tệp văn bản HIEU.INP
+ Dòng đầu ghi số N (N 10000)
+ Dòng thứ hai ghi n số nguyên cách nhau một dấu cách ( 1000);
Output: Tệp văn bản HIEU.OUT ghi số nguyên HIEU tìm được.
Ví dụ:
HIEU.INP HIEU.OUT
6 6
425817
Lời giải
Cách 1: Duyệt thử với tất cả các cặp chỉ số (i,j) với độ phức tạp O(n2)
MaxHieu:=0;
For i:=1 to n do

-16-
For j:=i to n do
If a[j]-a[i] > MaxHieu then MaxHieu:= A[j]-A[i];

Cách 2: Dùng phương pháp chia để trị chia mảng A thành 2 mảng con
a[1..k] và A[k..n] trong đó k = n div 2. Độ phức tạp sẽ giảm xuống còn O(nLgn)
Ta có: Hieu(A[1..n]) =Max(Hieu(A[k..n])-Min(Hieu(A[1..k]));

Chương trình
Program Hieu;
Const fi = 'Hieu.inp';
fo = 'Hieu.out';
maxn= 10000;
Var A:array[1..maxn] of longint;
n:longint;
maxd,mind,maxHieu:longint;

Procedure Docdl;
Var f:text;
i:longint;
Begin
Assign(f,fi); reset(f);
Readln(f,n);
For i:=1 to n do read(f,a[i]);
Close(f);
End;
Procedure Tim(l,r:longint; var maxhieu,maxd, mind:longint);
Var maxd1, mind1, maxhieu1, maxd2, mind2, maxhieu2, mid:longint;
Begin
If l=r then
Begin
maxd:=a[r];
mind:=a[r];
maxhieu:=0;
End
Else
Begin
mid:=(l+r) div 2;
Tim(l,mid,maxhieu1,maxd1,mind1);
Tim(mid+1,r,maxhieu2,maxd2,mind2);
maxhieu:=maxd2-mind1;
If maxhieu<maxhieu1 then maxhieu:=maxhieu1;
If maxhieu<maxhieu2 then maxhieu:=maxhieu2;
If maxd1>maxd2 then maxd:=maxd1 else maxd:=maxd2;
If mind1<mind2 then mind:=mind1 else mind:=mind2;
-17-
End;
End;

Procedure ghi;
var f:text;
Begin
assign(f,fo); rewrite(f);
writeln(f,maxHieu);
close(f);
End;
BEGIN
Docdl;
Tim(1,n,maxhieu,maxd, mind);
ghi;
END.

3. Đánh giá kết quả thực nghiệm.


Sau khi áp dụng đề tài này vào trong giảng dạy và bồi dưỡng cho học
sinh giỏi tin lớp 11 bước đầu đã thu được kết quả đáng kể.
- Trước khi áp dụng sáng kiến kinh nghiệm kết quả khảo sát cho các học
sinh giỏi khối 11 là:
+ Mức điểm giỏi: 0%
+ Mức điểm khá: 30%
+ Mức điểm TB: 55%
+ Mức điểm yếu: 15%
- Sau khi áp dụng sáng kiến kinh nghiệm kết quả khảo sát cho các học
sinh giỏi khối 11 là:
+ Mức điểm yếu giảm còn là: 0 %.
+ Mức điểm trung bình giảm còn là: 35%.
+ Mức điểm khá là: 57%
+ Mức điểm giỏi tăng lên là: 8%
Kết quả kỳ thi học sinh giỏi Tỉnh khối 11 đạt 02 giải KK

-18-
III. KẾT LUẬN

1. Ý nghĩa của đề tài, sáng kiến:


Đề tài này chỉ là một chuyên đề nhỏ nhằm giới thiệu đến học sinh phương
pháp và một số kỹ năng phân tích bài toán tin học thể hiện qua một số ví dụ từ
đơn giản đến nâng cao giúp học sinh bước đầu tiếp cận với bài toán tin học, biết
cách phân tích bài toán theo từng bước một để tìm ra cách giải và kỹ năng sử
dụng ngôn ngữ lập trình để cài đặt chương trình.
Tuy nhiên, do vẫn còn những hạn chế về trình độ hiểu biết chuyên môn,
thời gian thực hiện đề tài còn hạn hẹp. Do đó, trong đề tài chắc chắn sẽ không
tránh được những thiếu sót, rất mong sự đóng góp ý kiến của đồng nghiệp để đề
tài được hoàn thiện hơn.
2. Kiến nghị, đề xuất:
Là một giáo viên đang giảng dạy tại trường THPT tôi xin kiến nghị: Các
cơ quan ban ngành, nhà trường luôn tạo điều kiện về cơ sở vật chất, tinh thần
cho những giáo viên giảng dạy và bồi dưỡng học sinh giỏi. Đồng thời tạo điều
kiện cho GV được đi tập huấn để nâng cao trình độ. Tôi mong rằng với kiến
nghị này, các cơ quan ban ngành luôn tạo điều kiện và giúp đỡ.

-19-
IV. TÀI LIỆU THAM KHẢO

- Sáng tạo trong thuật toán và lập trình – Nguyễn Xuân Huy
- Tài liệu chuyên tin quyển 1 – Hồ Sỹ Đàm, Đỗ Đức Đông, Lê Minh
Hoàng, Nguyễn Thanh Hùng;
- Tài liệu tập huấn bồi dưỡng học sinh giỏi môn tin học ở trường THPT
của Sở GD-ĐT Quảng Bình
- Sưu tầm trên Internet.

-20-

You might also like