Chọn đến phần học sinh cần nhanh chóng thông qua mục lục bằng cách click đến phần đó
Câu hỏi mở đầu trang 127
Đề bài: Em được giao việc quản lí cho cửa hàng bán thực phẩm của gia đình. Hằng ngày em phải nhập danh sách các mặt hàng và doanh số bán hàng (tệp Data.inp). Cuối ngày, em cần báo cáo ba mặt hàng có doanh số cao nhất và ba mặt hàng có doanh số thấp nhất (tệp Data.out).
Em sẽ thiết kế chương trình như thế nào?
Lời giải:
Nên thiết kế chương trình chia thành các phần độc lập (mô đun), mỗi phần đảm nhận một chức năng riêng:
- Phần 1: Đọc dữ liệu từ tệp Data.inp vào chương trình (mảng tên mặt hàng và mảng doanh số).
- Phần 2: Xử lí dữ liệu – sắp xếp mảng theo doanh số.
- Phần 3: Ghi kết quả ra tệp Data.out – 3 mặt hàng có doanh số cao nhất và 3 mặt hàng có doanh số thấp nhất.
→ Cách thiết kế này giúp chương trình rõ ràng, dễ đọc, dễ chỉnh sửa khi có yêu cầu bổ sung.
1. Thiết kế chương trình theo mô đun
Hoạt động 1 trang 127
Đề bài: Thực hiện các bước thiết kế giải bài toán trên theo phương pháp làm mịn dần, trao đổi và thảo luận để biết được cách thiết kế chương trình theo mô đun.
Lời giải:
Bài toán được chia thành 3 công việc chính, mỗi công việc là một mô đun (hàm) riêng:
Bước 1 – Thiết kế chung:
- Công việc 1: Nhập dữ liệu từ tệp Data.inp.
- Công việc 2: Xử lí dữ liệu – sắp xếp theo doanh số.
- Công việc 3: Báo cáo – ghi ra tệp Data.out.
Bước 2 – Hàm NhapDL(fin): đọc dữ liệu từ tệp fin và trả về hai mảng P (tên mặt hàng) và S (doanh số).
def NhapDL(fin):
f = open(fin, encoding="UTF-8")
P = []
S = []
for line in f:
A = line.split(",")
P.append(A[0])
S.append(float(A[1]))
f.close()
return P, S
Bước 3 – Hàm Sapxep(A, B): sắp xếp hai mảng A, B theo thứ tự tăng dần của A.
def Sapxep(A, B):
n = len(A)
for i in range(1, n):
j = i
while j > 0 and A[j] < A[j-1]:
A[j], A[j-1] = A[j-1], A[j]
B[j], B[j-1] = B[j-1], B[j]
j = j - 1
Bước 4 – Hàm GhiDL(P, S, fout): ghi 3 mặt hàng có doanh số cao nhất và 3 mặt hàng có doanh số thấp nhất ra tệp fout.
def GhiDL(P, S, fout):
f = open(fout, "w", encoding="UTF-8")
n = len(P)
for i in range(n-1, n-4, -1): # 3 mặt hàng cao nhất (cuối dãy)
print(P[i], S[i], file = f)
for i in range(2, -1, -1): # 3 mặt hàng thấp nhất (đầu dãy)
print(P[i], S[i], file = f)
f.close()
Chương trình chính:
fin = "Data.inp"
fout = "Data.out"
P, S = NhapDL(fin)
Sapxep(S, P)
GhiDL(P, S, fout)
→ Kết luận: Chương trình được tách thành các mô đun con độc lập, chương trình chính chỉ gọi lần lượt các mô đun này.
Câu hỏi củng cố mục 1 trang 129
Đề bài:
1. Chương trình trên được thiết kế có bao nhiêu mô đun?
Lời giải:
Chương trình có 3 mô đun (3 hàm con):
NhapDL(fin): nhập dữ liệu.Sapxep(A, B): sắp xếp dữ liệu.GhiDL(P, S, fout): ghi dữ liệu ra tệp.
Ngoài ra còn có chương trình chính để gọi lần lượt 3 mô đun trên.
2. Các mô đun của chương trình trên có quan hệ với nhau như thế nào?
Lời giải:
- Ba mô đun độc lập với nhau, mỗi mô đun đảm nhận một chức năng riêng.
- Chương trình chính gọi các mô đun theo trình tự: nhập → sắp xếp → ghi.
- Dữ liệu được truyền qua tham số: hai mảng P và S là dữ liệu chung, được tạo ra bởi
NhapDL, được xử lí bởiSapxeprồi được đưa vàoGhiDL.
2. Lợi ích của phương pháp thiết kế theo mô đun
Hoạt động 2 trang 129
Đề bài: Với chương trình đã có trong Hoạt động 1, em sẽ làm gì nếu có các yêu cầu bổ sung sau:
1. Yêu cầu thay đổi thông tin trong báo cáo: Ghi hai mặt hàng có doanh số cao nhất và bốn mặt hàng có doanh số thấp nhất.
2. Cập nhật, bổ sung các mặt hàng mới và doanh số trong ngày.
3. Yêu cầu làm thêm một báo cáo trong đó ghi doanh số bán trung bình trong ngày và danh sách các mặt hàng có doanh số lớn hơn doanh số trung bình này, kết quả đưa ra tệp Data2.out.
Lời giải:
Công việc bổ sung 1 – Nâng cấp hàm GhiDL(): chỉ cần sửa hai dòng lệnh (dòng 4 và dòng 6).
def GhiDL(P, S, fout):
f = open(fout, "w", encoding="UTF-8")
n = len(P)
for i in range(n-1, n-3, -1): # 2 mặt hàng cao nhất (đổi n-4 → n-3)
print(P[i], S[i], file = f)
for i in range(3, -1, -1): # 4 mặt hàng thấp nhất (đổi 2 → 3)
print(P[i], S[i], file = f)
f.close()
Công việc bổ sung 2: chỉ cần mở tệp Data.inp và thêm dữ liệu, không cần sửa chương trình.
Công việc bổ sung 3 – Tạo mô đun mới BC2(): hoàn toàn độc lập với các mô đun cũ.
def BC2(P, S, fout):
f = open(fout, "w", encoding="UTF-8")
n = len(P)
average = sum(S)/n
print("Doanh số trung bình:", average, file = f)
for i in range(n):
if S[i] > average:
print(P[i], S[i], file = f)
f.close()
Trong chương trình chính, thêm lệnh:
BC2(P, S, "Data2.out")
Nhận xét: Nhờ thiết kế theo mô đun, việc bổ sung, nâng cấp trở nên rất đơn giản, không phải sửa lại toàn bộ chương trình.
Câu hỏi củng cố mục 2 trang 131
Đề bài:
1. Phân loại các công việc bổ sung trên vào ba loại sau:
– Công việc mới hoàn toàn.
– Công việc nâng cấp một mô đun cũ.
– Công việc không liên quan đến thuật toán và lập trình.
Lời giải:
| Công việc bổ sung | Loại |
|---|---|
| Công việc 1 – Thay đổi thông tin báo cáo | Nâng cấp mô đun cũ (sửa hàm GhiDL) |
| Công việc 2 – Cập nhật mặt hàng mới | Không liên quan đến thuật toán và lập trình (chỉ thêm dữ liệu vào tệp) |
| Công việc 3 – Báo cáo doanh số trung bình | Công việc mới hoàn toàn (tạo hàm BC2 mới) |
2. Công việc sau đây, nếu có, sẽ thuộc nhóm công việc nào? Nhập một giá trị số nào đó, ví dụ K, cần tìm trong danh sách các mặt hàng có doanh số xấp xỉ K (hơn kém nhau không quá hằng số C = 1).
Lời giải:
Đây là công việc mới hoàn toàn – vì trong chương trình cũ chưa có mô đun nào thực hiện chức năng tìm kiếm theo doanh số. Cần tạo thêm một hàm mới, ví dụ:
def TimXapXi(P, S, K, C):
ket_qua = []
for i in range(len(S)):
if abs(S[i] - K) <= C:
ket_qua.append(P[i])
return ket_qua
Luyện tập
Luyện tập trang 131
Đề bài:
1. Nếu công việc bổ sung 3 có thêm yêu cầu in ra số lượng mặt hàng đã bán trong ngày thì cần thêm hay sửa lệnh nào của chương trình BC2()?
Lời giải:
Chỉ cần thêm 1 lệnh in ra biến n (số lượng mặt hàng) vào hàm BC2().
def BC2(P, S, fout):
f = open(fout, "w", encoding="UTF-8")
n = len(P)
print("Số lượng mặt hàng:", n, file = f) # dòng thêm
average = sum(S)/n
print("Doanh số trung bình:", average, file = f)
for i in range(n):
if S[i] > average:
print(P[i], S[i], file = f)
f.close()
→ Chỉ thêm 1 dòng lệnh, không cần sửa các dòng khác.
2. Viết thêm một chương trình cho công việc bổ sung 4 như sau: Cần in ra danh sách $\dfrac{1}{3}$ số mặt hàng có doanh số thấp nhất trong ngày.
Lời giải:
Với n mặt hàng, cần in ra $\dfrac{n}{3}$ mặt hàng có doanh số thấp nhất. Vì dãy đã được sắp xếp tăng dần theo doanh số (nhờ hàm Sapxep), ta chỉ cần in ra các phần tử đầu dãy.
def BC4(P, S, fout):
f = open(fout, "w", encoding="UTF-8")
n = len(P)
so_luong = n // 3 # 1/3 số mặt hàng (chia lấy nguyên)
for i in range(so_luong):
print(P[i], S[i], file = f)
f.close()
Trong chương trình chính, thêm lệnh:
BC4(P, S, "Data4.out")
Giải thích:
n // 3là phép chia lấy phần nguyên → số mặt hàng cần in.- Duyệt các chỉ số từ 0 đến
so_luong – 1, in ra tên và doanh số của mỗi mặt hàng.
Vận dụng
Vận dụng trang 131
Đề bài:
1. Thiết lập chương trình cho công việc thường làm vào cuối giờ bán hàng: Cho trước số K (một doanh số giả định), cần tìm ra mặt hàng có doanh số nhỏ hơn K nhưng gần với K nhất. Bài toán này có thể sử dụng thuật toán tìm kiếm nào để giải?
Lời giải:
Bài toán này có thể giải bằng tìm kiếm tuần tự (nếu dãy chưa sắp xếp) hoặc tìm kiếm nhị phân (nếu dãy S đã được sắp xếp tăng dần).
Chương trình dùng tìm kiếm tuần tự:
def TimGanK(P, S, K):
ket_qua = -1 # chỉ số mặt hàng cần tìm
gan_nhat = -1 # doanh số gần K nhất (nhỏ hơn K)
for i in range(len(S)):
if S[i] < K:
if S[i] > gan_nhat:
gan_nhat = S[i]
ket_qua = i
return ket_qua
Giải thích:
- Duyệt lần lượt qua các mặt hàng.
- Với mỗi mặt hàng có doanh số nhỏ hơn K, so sánh với
gan_nhathiện tại. Nếu lớn hơn thì cập nhật. - Kết thúc,
ket_qualà chỉ số của mặt hàng cần tìm.
2. Thiết kế thuật toán và chương trình theo mô đun cho bài toán sau:
Cho n địa điểm tham quan được đánh số 0, 1, 2, …, n–1. Mỗi khách hàng gửi lên công ty một dãy n số đánh giá (có thể là số dương, 0 hoặc số âm). Cần tìm tour du lịch tối ưu là một dãy các vị trí liên tục từ i đến j sao cho tổng các đánh giá là lớn nhất.
Lời giải:
Ý tưởng: Duyệt tất cả các cặp (i, j) với i ≤ j, tính tổng A[i] + A[i+1] + … + A[j], giữ lại tour có tổng lớn nhất. Dùng 2 vòng lặp lồng nhau.
Thiết kế theo mô đun:
- Mô đun 1 –
DocDL(fin): đọc dãy đánh giá A từ tệp. - Mô đun 2 –
TimTour(A): tìm cặp (i, j) cho tổng lớn nhất. - Mô đun 3 –
GhiKQ(i, j, tong, fout): ghi kết quả ra tệp.
Chương trình cụ thể:
def DocDL(fin):
f = open(fin, encoding="UTF-8")
A = f.readline().split()
for i in range(len(A)):
A[i] = int(A[i])
f.close()
return A
def TimTour(A):
n = len(A)
max_tong = A[0]
best_i = 0
best_j = 0
for i in range(n):
tong = 0
for j in range(i, n):
tong = tong + A[j]
if tong > max_tong:
max_tong = tong
best_i = i
best_j = j
return best_i, best_j, max_tong
def GhiKQ(i, j, tong, fout):
f = open(fout, "w", encoding="UTF-8")
print("Tour tối ưu từ địa điểm", i, "đến địa điểm", j, file = f)
print("Tổng đánh giá:", tong, file = f)
f.close()
# Chương trình chính
A = DocDL("input.txt")
i, j, tong = TimTour(A)
GhiKQ(i, j, tong, "output.txt")
Giải thích hàm TimTour:
- Vòng ngoài chạy
itừ 0 đến n – 1 (điểm bắt đầu tour). - Với mỗi
i, đặt biếntong = 0, rồi vòng trong chạyjtừiđến n – 1, cộng dồn A[j] vào tổng. - Nếu tổng hiện tại lớn hơn
max_tongthì cập nhậtmax_tong,best_i,best_j. - Cuối cùng trả về cặp (best_i, best_j) và tổng lớn nhất tương ứng.
Ví dụ: Với dãy [1, –3, 4, 10, 0, –5, –8, 2, –1, 7, 2], tour tối ưu là từ i = 2 đến j = 3 với tổng bằng 14 (4 + 10).

Thầy Phạm Thành Danh
(Người kiểm duyệt, ra đề)
Chức vụ: Trưởng ban biên soạn môn Tin Học THPT
Trình độ: Cử nhân Sư phạm Tin học, Chứng chỉ hạng II, Chứng chỉ Tin học, Ngoại ngữ B1
Kinh nghiệm: 8+ năm kinh nghiệm tại Trường THPT Thuận Hóa
