SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HÓATRƯỜNG THPT HOẰNG HÓA 4 ------SÁNG KIẾN KINH NGHIỆM ĐỀ TÀI “TẠO TEST NGẪU NHIÊN CHO MỘT SỐ BÀI TOÁN ÔN THI HỌC SINH GIỎI BẰNG NGÔN NGỮ LẬP TRÌNH C++”
Trang 1SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HÓA
TRƯỜNG THPT HOẰNG HÓA 4
- -SÁNG KIẾN KINH NGHIỆM
ĐỀ TÀI
“TẠO TEST NGẪU NHIÊN CHO MỘT SỐ BÀI TOÁN
ÔN THI HỌC SINH GIỎI BẰNG NGÔN NGỮ
LẬP TRÌNH C++”
Người thực hiện: Trương Ngọc Huy
SKKN thuộc môn: Tin học
THANH HOÁ NĂM 2024
Trang 2MỤC LỤC
Trang
1 MỞ ĐẦU 1
1.1 Lí do chọn đề tài: 1
1.2 Mục đích nghiên cứu: 1
1.3 Đối tượng nghiên cứu: 1
1.4 Phương pháp nghiên cứu: 1
1.5 Những điểm mới của sáng kiến kinh nghiệm: 2
2 NỘI DUNG SÁNG KIẾN KINH NGHIỆM 2
2.1 Cơ sở lý luận của sáng kiến kinh nghiệm: 2
2.2 Thực trạng vấn đề trước khi áp dụng sáng kiến kinh nghiệm: 3
2.3 Các giải pháp đã sử dụng để giải quyết vấn đề: 3
2.3.1 Tạo một số, kí tự ngẫu nhiên sử dụng hàm srand và rand: 3
a Tạo một số nguyên ngẫu nhiên có giá trị thuộc đoạn [0, x]: 3
b Tạo một số nguyên ngẫu nhiên có giá trị thuộc đoạn [-x, x]: 4
c Tạo số nguyên ngẫu nhiên từ x đếm y(x<y): 4
d Tạo một kí tự ngẫu nhiên: 4
e Tạo một số thực ngẫu nhiên: 5
2.3.2 Tạo một số, xâu kí tự ngẫu nhiên sử dụng cách thức khác: 5
a Tạo số nguyên ngẫu nhiên sử dụng lớp mt19937 hoặc mt19937_64: 5
b Tạo số nguyên ngẫu nhiên sử dụng lớp default_random_engine và uniform_int_distribution: 6
c Tạo số thực ngẫu nhiên: 6
d Tạo xâu kí tự ngẫu nhiên: 6
2.3.3 Tạo mãng N số ngẫu nhiên, xâu kí tự có độ dài ngẫu nhiên: 7
a Tạo mảng a gồm N số ngẫu nhiên không âm: 7
b Tạo mảng a gồm N số ngẫu nhiên: 8
c Tạo mảng a gồm N số nguyên ngẫu nhiên từ x đến y: 8
d Tạo mảng a gồm N số thực ngẫu nhiên: 8
e Tạo xâu kí tự có độ dài ngẫu nhiên: 9
f Tạo mảng a gồm N xâu kí tự có độ dài ngẫu nhiên: 10
2.3.4 Một số bài toán hay dùng trong ôn thi học sinh giỏi: 11
Bài toán 1: Tạo mảng ngẫu nhiên tăng 11
Bài toán 2: Tạo mảng cấp số cộng 11
Bài toán 3: Tạo ngẫu nhiên mảng có tỉ lệ 1:k 12
Bài toán 4: Tạo ngẫu nhiên đều 13
Bài toán 5: Tạo xâu đối xứng ngẫu nhiên 14
2.4 Hiệu quả của sáng kiến kinh nghiệm: 15
Trang 33 KẾT LUẬN VÀ KIẾN NGHỊ 16
3.1 Kết luận: 16
3.2 Kiến nghị: 17
TÀI LIỆU THAM KHẢO 18
DANH MỤC 19
Trang 41 MỞ ĐẦU 1.1 Lí do chọn đề tài:
Trong mọi thời đại, giáo dục luôn đóng vai trò vô cùng quan trọng Đó là
nền tảng, là động lực cho sự phát triển của một quốc gia Để đào tạo thế hệ trẻ
trở thành người chủ thực sự của đất nước trong tương lai, có khả năng làm chủđược nền khoa học kỹ thuật hiện đại, thì việc đổi mới nội dung và phươngpháp dạy học là vấn đề hết sức cấp thiết Một trong những biện pháp giúp đổimới phương pháp dạy học hiện nay là ứng dụng công nghệ thông tin trong dạyhọc và trong đời sống xã hội Với sự giúp đỡ của máy vi tính và các phần mềmdạy học, giáo viên sẽ tổ chức tốt quá trình dạy học trên lớp theo hướng phát huytính tích cực, chủ động, sáng tạo trong hoạt động nhận thức của học sinh
Trong quá trình tham gia giảng dạy và bồi dưỡng học sinh giỏi môn Tinhọc ở trường, tôi thấy việc tạo test để chấm bài cho học sinh là một công việchết sức quan trọng Vì khi tham gia các kì thi liên quan đến lập trình trong Tinhọc thì chúng ta cần có test để chấm Để có được test chấm thì chúng ta phảitạo ra các test bằng tay hoặc bằng code tạo ra file input của bài toán, từ fileinput của bài toán ta chạy trương trình code chuẩn hoặc code trâu để sinh rafile output đúng Một bộ test chuẩn là bộ test phải vét được tất cả các trườnghợp của bài toán
Chính vì vậy tôi nhận thấy để đánh giá chính xác được thuật toán của 1bài toán trong Tin học có tối ưu hay không thì việc tạo test là rất quan trọng Đó
chính là lý do, tôi đã chọn đề tài " Tạo test ngẫu nhiên cho một số bài toán ôn thi học sinh giỏi bằng ngôn ngữ lập trình C++" để nghiên cứu.
1.2 Mục đích nghiên cứu:
Tạo ra một số chương trình tạo test để chấm các bài toán cơ bản và nângcao trong quá trình ôn thi học sinh giỏi Giúp học sinh tìm ra các thuật toán tối
ưu hơn và giúp giáo viên chấm bài một cách nhanh chóng và hiệu quả
1.3 Đối tượng nghiên cứu:
- Các khái niệm về hàm và các phương thức khác có liên quan đến tạo testngẫu nhiên;
- Học sinh khối 10 và một số học sinh ôn thi học sinh giỏi của trườngTHPT Hoằng Hóa 4
1.4 Phương pháp nghiên cứu:
- Tìm hiểu các hàm và các phương thức khác có liên quan đến tạo testngẫu nhiên;
- Sáng kiến kinh nghiệm của tôi đang trình bày dựa theo các phương phápnhư: Thuyết trình, quan sát, phân tích thuật toán, … phù hợp với bài học và mônhọc thuộc lĩnh vực Tin học
Trang 51.5 Những điểm mới của sáng kiến kinh nghiệm:
- Hiện nay có nhiều giáo viên giảng dạy môn Tin học hoặc những em họcsinh muốn học về lập trình nhưng chưa biết cách tạo test để chấm bài chochương trình của mình hay của học sinh Vì vậy khi biết tạo file input ngẫunhiên thì công việc tạo test chấm bài được thực hiện một cách nhanh chóng vàhiệu quả hơn
- Đề tài này tôi đã vận dụng thêm một số phương thức khác để tạo test
ngoài hàm rand() và vận dụng vào một số bài toán cụ thể để tạo test nhằm tối
ưu thuật toán
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:
Từ nghị quyết số 29/NQ-TW tại Hội nghị Trung ương 8 khóa XI về đổimới căn bản, toàn diện giáo dục và chỉ thị 40/CT của Ban bí thư Trung ươngĐảng, sở GD&ĐT đã tập trung chỉ đạo đổi mới các hoạt động kiểm tra, đánh giáthúc đẩy đổi mới phương pháp dạy học nhằm tạo sự chuyển biến cơ bản về tổchức hoạt động dạy học, góp phần nâng cao chất lượng giáo dục trong các nhàtrường
Môn tin học có nhiều đặc thù khác nhau, khác nhau ở từng cấp học, khốilớp Từ người bắt đầu sử dụng máy tính, đến người đã sử dụng thành thạo máytính Tuy nhiên cấp học cao hơn thì chương trình học cũng cao hơn Một sự khácbiệt nửa của môn Tin học là Lý thuyết – Bài tập – Thực hành hay nói cách khác
là Nói – Làm – Có kết quả, nói chung phải đạt cả ba Chẳng hạn dạy học lậptrình người dạy dạy lý thuyết hay, giải bài tập hay và thực hành cho kết quảminh chứng, nhưng nếu khi thực hành trên máy không cho kết quả như mongmuốn thì chữ hay đó chắc chắn không trọn vẹn
Mặt khác tuy môn Tin học mới đưa vào chương trình phổ thông bắt từnăm 2006, nhưng hiện nay có rất nhiều học sinh biết những kiến thức cơ bản vềthông tin và các công nghệ cao là những kiến thức rất cần thiết đối với mỗingười nhất là thế hệ trẻ hiện nay Vì vậy các em đã đam mê hơn với môn Tinhọc và muốn học lập trình để theo ngành công nghệ thông tin Nhưng do điềukiện kinh tế của gia đình không mua được máy tính cho học sinh cũng như cơ sởvật chất của nhà trường còn thiếu nên cơ sở vật chất để giảng dạy môn học nàycũng không dễ mua sắm Từ những bất cập đó mà trình độ hiểu biết về lập trìnhnói riêng và tin học nói chung trong nhà trường còn hạn chế
Một trong những hạn chế ở đây là học sinh sau khi lập trình giải quyếtđược 1 bài toán trong tin học nhưng không biết có đúng theo yêu cầu của bàitoán không và làm sao biết để tối ưu được thuật toán của bài toán đã cho? Điềunày đã hối thúc tôi tìm tòi và nghiên cứu để tìm ra giải pháp nhằm mục đích dạytốt hơn trong quá trình ôn thi học sinh giỏi nói riêng và học lập trình nói chungtrong nhà trường
Trang 62.2 Thực trạng vấn đề trước khi áp dụng sáng kiến kinh nghiệm:
Ngày nay phần lớn học sinh biết sử dụng máy tính và có máy tính cá nhânmỗi ngày một tăng, trình độ hiểu biết và sử dụng máy tính cũng tăng rõ rệt.Nhiều em đã định hướng được ngành nghề cho tương lai nên đã đam mê hơn vớimôn Tin học, nhất là lập trình giải quyết các bài toán trong Tin học Đồng thờinhiều em cũng muốn được vào đội tuyển thi học sinh giỏi cấp Tỉnh của trường
Tuy nhiên cơ sở vật chất của nhà trường không đáp ứng được các tiết thựchành và tài liệu học tập của môn Tin học trong nhà trường còn khá ít Thời gianhọc tập trên trường cũng hạn chế nên phần lớn các em học và làm bài tập ở nhànhưng không biết chương trình của mình đã đúng với yêu cầu của đề bài chưa
Chính vì vậy để biết một chương trình đã đúng chưa và làm sao để tránhsai sót và tối ưu được thuật toán thì cần phải có nhiều bộ test khác nhau và vétđược hết các trường hợp của bài toán cho Đó chính là thực trạng của của vấn đềtrước khi áp dụng sáng kiến kinh nghiệm này
2.3 Các giải pháp đã sử dụng để giải quyết vấn đề:
Trong ngôn ngữ lập trình C++ hàm rand() tạo một số nguyên ngẫu nhiên trong đoạn [0, RAND_MAX], trong đó RAND_MAX là một hằng số có sẵn có
giá trị phụ thuộc vào chương trình dịch Giá trị lớn nhất của số nguyên tạo ra bởi
rand() là RAND_MAX, thường là 32767 Dựa vào hàm rand này tôi đưa ra một
số chương trình tạo test cho một số bài tập đơn giản và nâng cao trong các bàitập bồi dưỡng học sinh giỏi Trước khi gọi hàm rand ta cần gọi hàm srand để
khởi tạo bộ số ngẫu nhiên Tuy nhiên C++ còn cung cấp nhiều cách thức để tạo
dữ liệu ngẫu nhiên khác như sử dụng lớp mt19937, mt19937_64,
default_random_engine, uniform_real_distribution, uniform_int_distribution
sẽ được tôi lồng ghép vào một số nội dung,
2.3.1 Tạo một số, kí tự ngẫu nhiên sử dụng hàm srand và rand:
a Tạo một số nguyên ngẫu nhiên có giá trị thuộc đoạn [0, x]:
freopen("SND.INP","w", stdout); //Ghi giá trị vào file SND.INP
Trang 7b Tạo một số nguyên ngẫu nhiên có giá trị thuộc đoạn [-x, x]:
freopen("SNDXX.INP","w", stdout); //Ghi giá trị vào file SNDXX.INP
c Tạo số nguyên ngẫu nhiên từ x đếm y(x<y):
Ta có rand()%(y-x+1) tạo số nguyên ngẫu nhiên từ 0 đếm y-x do đóx+rand()%(y-x+1) tạo các số từ x đến x+y-x=y Từ nhận xét đó ta có đoạnchương trình sau:
freopen("SNDXY.INP","w", stdout); //Ghi giá trị vào file SNDXY.INP
d Tạo một kí tự ngẫu nhiên:
Ta có các kí tự trong bảng mã ASCII có mã thập phân tử 0 đến 255 do đó
ta sử dụng cách ép kiểu nguyên về kí tự Cách ép kiểu nguyên về kí tự như sau
freopen("KITU.INP","w", stdout); //Ghi giá trị vào file KITU.INP
Trang 8freopen("SOTHUC.INP","w", stdout); //Ghi giá trị vào file SOTHUC.INP
float x = 1, y = 100;
float n = x + z*(y-x); //Tạo số thực trong đoạn [x, y](1, 100)
ôn luyện học sinh giỏi một cách dễ dàng từ đó có thể đánh giá các giải thuật củahọc sinh một cách chính xác
2.3.2 Tạo một số, xâu kí tự ngẫu nhiên sử dụng cách thức khác:
a Tạo số nguyên ngẫu nhiên sử dụng lớp mt19937 hoặc mt19937_64:
Lớp mt19937 sử dụng để tạo ra số nguyên 32-bit, lớp mt19937_64 sửdụng để tạo ra số nguyên 64-bit Sau đây là chương trình minh họa cách sửdụng 2 lớp này
Trang 9c Tạo số thực ngẫu nhiên:
Hàm rand và lớp mt19937 chỉ tạo ra số nguyên, để tạo ra số thực bạnphải sử dụng phép nhân số nguyên tạo ra với 1.0 và sau đó chia các số tạo racho nhau Một cách khác để tạo ra số thực ngẫu nhiên là sử dụng lớp
default_random_engine, uniform_real_distribution tương tự như với sốnguyên Sau đây là chương trình minh họa tạo số thực ngẫu nhiên có giá trịtrong đoạn [1, 1000]
d Tạo xâu kí tự ngẫu nhiên:
Để tạo xâu kí tự ngẫu nhiên, ta thực hiện theo các bước như sau:
- Định nghĩa một xâu/mảng kí tự làm bảng kí tự từ điển;
- Sử dụng cấu trúc lặp gọi hàm tạo số ngẫu nhiên nhiều lần, lấy giá trị số
Trang 10ngẫu nhiên đó chia lấy phần dư cho một số(thường là tổng số kí tự của bảng kí
tự từ điển) cho để làm chỉ số truy cập lấy kí tự ngẫu nhiên từ bảng kí tự từ điển
Sau đây là chương trình minh họa tạo ra xâu kí tự ngẫu nhiên có độ dàitối đa 100 kí tự là chữ latin viết thường và chỉ có 4 kí tự là: ‘a’, ‘b’, ‘c’, ‘d’:
string dict = "abcd"; //Từ điển
string rnds = ""; //Xâu ngẫu nhiên tạo ra
int len = mt() % 100; //Độ dài xâu
for (int i = 1; i <= len; i++){
2.3.3 Tạo mãng N số ngẫu nhiên, xâu kí tự có độ dài ngẫu nhiên:
Tạo ngẫu nhiên N số, kí tự ngẫu nhiên sử dụng kiểu dữ liệu mảng để lưu
a Tạo mảng a gồm N số ngẫu nhiên không âm:
freopen("ARRD.INP","w", stdout); //Ghi giá trị vào file ARRD.INP
int x = 100, y = 1000;
int n = rand()%(x+1);//Tạo số lượng phần tử thuộc đoạn 0 x(0 100)
cout<<n<<endl;
for(int i = 1; i <= n; i++){
a[i] = rand ()%(y+1); //Tạo số nguyên dương thuộc đoạn 0 y(0 1000) cout <<a[i]<<" ";
}
return 0;
}
Trang 11b Tạo mảng a gồm N số ngẫu nhiên:
freopen("ARRAD.INP","w", stdout); //Ghi giá trị vào file ARRAD.INP
int x = 100, y = 1000;
int n = rand()%(x+1); //Tạo số lượng phần tử thuộc đoạn 0 x(0 100)
cout<<n<<endl;
for(int i = 1; i <= n; i++){
a[i] = rand ()%(y+1) - rand ()%(y+1); //Tạo số nguyên dương thuộc đoạn -y y(-1000 1000)
cout <<a[i]<<" ";
}
return 0;
}
c Tạo mảng a gồm N số nguyên ngẫu nhiên từ x đến y:
Dựa vào nhận xét của mục 2.3.1 c ta có thủ tục tạo n số nguyên ngẫunhiên tử x đến y(x<y) như sau:
freopen("ARRXY.INP","w", stdout); //Ghi giá trị vào file ARRXY.INP
int z = 100, x = 10, y = 1000;
int n = rand()%(z+1);//Tạo số lượng phần tử thuộc đoạn 0 z(0 100)
cout<<n<<endl;
for(int i = 1; i <= n; i++){
a[i] = x + rand()%(y-x+1); //Tạo số nguyên dương thuộc đoạn x y(10 1000)
cout <<a[i]<<" ";
}
return 0;
}
d Tạo mảng a gồm N số thực ngẫu nhiên:
Sử dụng đoạn chương trình tạo một số thực ở mục 2.3.1 e ta sẽ có một
Trang 12mảng ngẫu nhiên gồm n số thực như sau:
freopen("ARRTHUC.INP","w", stdout); //Ghi giá trị vào file ARRTHUC.INP
int m = 100;
int n = rand()%(m+1);//Tạo số lượng phần tử thuộc đoạn 0 m(0 100)
cout<<n<<endl;
float x = 10, y = 10000;
for(int i = 1; i <= n; i++){
float z = rand()/(float) RAND_MAX; //Tạo số thực trong đoạn [0, 1.0]
a[i] = x + z*(y-x); //Tạo số thực trong đoạn [x, y](10, 10000)
cout << fixed<<setprecision(2)<<a[i]<<" ";
}
return 0;
}
e Tạo xâu kí tự có độ dài ngẫu nhiên:
Sau đây tôi sẽ đưa ra một chương trình tạo một xâu ngẫu nhiên gồm chữcái thường, Hoa và số, các trường hợp còn lại làm tương tự
freopen("XAUtHS.INP","w", stdout); //Ghi giá trị vào file XAUtHS.INP
int m = 100;
int n = rand()%(m+1); //Số lượng kí tự trong xâu
int x = 96;
for(int i = 1; i <= 26; i++){
x++; a[i] = (char)x; //Mảng kí tự in thường a z
}
x = 64;
for(int i = 27; i <= 52; i++){
x++; a[i] = (char)x; //Mảng kí tự in HOA A Z
Trang 13for(int i = 1; i <= n; i++){
cout<<a[rand()%62 + 1]; //Tạo xâu ngẫu nhiên gồm chữ in thường, in HOA và chữ số //cout<<a[rand()%52 + 1]; //Tạo xâu ngẫu nhiên gồm chữ in thường và in HOA }
freopen("ARRXAU.INP","w", stdout); //Ghi giá trị vào file ARRXAU.INP
int x = 96;
for(int i = 1; i <= 26; i++){
x++; a[i] = (char)x; //Mảng kí tự in thường a z
}
x = 64;
for(int i = 27; i <= 52; i++){
x++; a[i] = (char)x; //Mảng kí tự in HOA A Z
int n = rand()%(z+1); //n là số lượng kí tự trong 1 xâu
int m = rand()%(y+1); //m là số lượng phần tử của mảng xâu
cout<<m<<endl;
for(int j=1; j<=m; j++) {
for(int i=1; i<=n;i++)
//cout<<a[rand()%52+1]; //Tạo 1 xâu gồm n phần tử gồm chữ cái thường và Hoa
cout<<a[rand()%62+1]; //Tạo 1 xâu gồm n phần tử gồm chữ cái thường, Hoa và số
//cout<<(char)(x+rand()%(y-x+1); //Tạo ra xâu ngẫu nhiên từ x -> y
//cout<<(char)(97+rand()%(122-97+1)); //Tạo ra xâu gồm n kí tự ngẫu nhiên từ 'a'->'z'