Giải Tin Học 10 trang 153
Lời giải chi tiết SGK Lớp 10 · Môn Tin Há»c · Trang 153–156
Bài 32: Ôn Tập Lập Trình Python
🔍 Kiến thức cần nhớ
Bài này ôn tập tổng hợp các kỹ thuật lập trình Python đã học và vận dụng vào bài toán liên môn (Toán, Vật lí, Lịch).
Các công cụ cần dùng lại:
- Xử lý xâu: lệnh
split()tách một xâu thành danh sách các từ, lệnh" ".join(ds)ghép danh sách thành xâu. - Cắt xâu/danh sách (slicing):
ds[1:-1]lấy phần ở giữa,ds[0]lấy phần tử đầu,ds[-1]lấy phần tử cuối. - Danh sách (list): truy cập theo chỉ số, dùng
len()để lấy độ dài, dùng vòngforđể duyệt. - Câu lệnh điều kiện
if … else, vòng lặpfor,while. - Hàm
def, kiểu dữ liệu sốint,float, ép kiểustr(),int(),float().
Hai công thức Vật lí dùng trong bài:
- Trọng lượng: P = m × g
- Suy ra trọng lượng trên hành tinh khác: P' = P × g'/g (với g trên Trái Đất ≈ 9.8 m/s²)
💡 Mẹo nhớ:split()"xẻ" xâu thành nhiều mảnh → danh sách;join()"may" các mảnh lại thành một xâu. Cặp đôi này luôn đi cùng nhau khi xử lý họ tên.
⚙️ Bài tập
Câu 1 — Nhiệm vụ 1: Tách họ, đệm, tên
Đề bài: Viết chương trình nhập họ tên đầy đủ từ bàn phím (ví dụ Nguyễn Thị Mai Hương), sau đó tách riêng phần họ, phần đệm và phần tên rồi in ra màn hình.
Phân tích:
Khi tách xâu họ tên bằng split(), ta được một danh sách. Quy ước:
- Phần tử đầu tiên
ds[0]là họ. - Phần tử cuối cùng
ds[-1]là tên. - Các phần tử ở giữa
ds[1:-1]là đệm (có thể có nhiều từ hoặc không có).
Cách 1 — Dùng slicing và join
ho_ten = input("Nhập họ tên đầy đủ: ")
ds = ho_ten.split() # tách thành danh sách các từ
n = len(ds)
ho = ds[0] # phần tử đầu là họ
ten = ds[n - 1] # phần tử cuối là tên
dem = " ".join(ds[1:n - 1]) # ghép các từ ở giữa thành phần đệm
print("Họ:", ho)
print("Tên:", ten)
if dem != "": # chỉ in đệm khi có
print("Đệm:", dem)
Chạy thử với "Nguyễn Thị Mai Hương":
Họ: Nguyễn
Tên: Hương
Đệm: Thị Mai
Cách 2 — Dùng phép gán nhiều biến gọn hơn
ho_ten = input("Nhập họ tên đầy đủ: ")
ds = ho_ten.split()
ho, *dem, ten = ds # gán linh hoạt: đầu là họ, cuối là tên, giữa là đệm
print("Họ:", ho)
print("Tên:", ten)
print("Đệm:", " ".join(dem) if dem else "(không có)")
Toán tử *dem gom tất cả phần tử còn lại ở giữa vào danh sách dem. Cách này ngắn và dễ đọc.
⚠️ Lưu ý thi: Phải dùngds[1:-1](hoặc*dem) cho phần đệm, không viết cứngds[1]vì đệm có thể có nhiều từ hoặc không có từ nào.
Câu 2 — Nhiệm vụ 2: Tính trọng lượng trên các hành tinh khác
Đề bài: Chương trình yêu cầu nhập trọng lượng của em tính theo đơn vị N (Newton) trên Trái Đất, rồi tính trọng lượng của em trên một hành tinh khác (ví dụ: Mặt Trăng, Hỏa tinh, Kim tinh, Thổ tinh, Mộc tinh, Mặt Trời).
Phân tích:
Khối lượng m không đổi: m = P/g. Trên Trái Đất g = 9.8 m/s². Trên hành tinh khác có gia tốc g', trọng lượng mới là:
P' = m × g' = (P/9.8) × g' = P × g'/9.8
Ta lưu tên các hành tinh trong danh sách Names và gia tốc trọng trường tương ứng trong danh sách g.
Cách 1 — Dùng hàm và vòng lặp (theo sách)
# weight.py
Names = ['Mặt Trăng', 'Hỏa tinh', 'Kim tinh',
'Mộc tinh', 'Thổ tinh', 'Mặt Trời']
g = [1.62, 3.71, 8.87, 24.79, 10.44, 274.0]
g_traidat = 9.8
def kqua(P):
s = ""
for i in range(len(Names)):
Pmoi = P * g[i] / g_traidat # P' = P × g'/9.8
s = s + Names[i] + ": " + str(round(Pmoi, 2)) + " N\n"
return s
P = float(input("Nhập trọng lượng của em trên Trái Đất (N): "))
print("Trọng lượng của em trên các hành tinh khác:")
print(kqua(P))
Chạy thử với P = 490 N:
Trọng lượng của em trên các hành tinh khác:
Mặt Trăng: 81.0 N
Hỏa tinh: 185.5 N
Kim tinh: 443.5 N
Mộc tinh: 1239.5 N
Thổ tinh: 522.0 N
Mặt Trời: 13700.0 N
Cách 2 — Duyệt song song hai danh sách bằng zip
Names = ['Mặt Trăng', 'Hỏa tinh', 'Kim tinh',
'Mộc tinh', 'Thổ tinh', 'Mặt Trời']
g = [1.62, 3.71, 8.87, 24.79, 10.44, 274.0]
P = float(input("Nhập trọng lượng của em trên Trái Đất (N): "))
for ten, gia_toc in zip(Names, g):
print(ten, ":", round(P * gia_toc / 9.8, 2), "N")
zip(Names, g) ghép từng cặp (tên, gia tốc) lại, giúp duyệt hai danh sách cùng lúc mà không cần dùng chỉ số i.
💡 Mẹo nhớ: Trọng lượng đổi theo hành tinh nhưng khối lượng không đổi. Chỉ cần nhân thêm tỉ số g'/9.8 là ra trọng lượng mới.
Câu 3 — Nhiệm vụ 3: Kiểm tra tính hợp lệ của ngày, tháng, năm
Đề bài: Nhập ba số tự nhiên ngày, tháng, năm theo khuôn dạng (ví dụ "21-3-2024"). Chương trình thông báo bộ dữ liệu đã nhập là hợp lệ hay không hợp lệ. Chú ý kiểm tra năm nhuận: nếu là năm nhuận thì tháng 2 có 29 ngày, năm không nhuận tháng 2 có 28 ngày.
Phân tích:
- Năm nhuận khi: chia hết cho 400, hoặc (chia hết cho 4 và không chia hết cho 100).
- Lưu số ngày của 12 tháng vào danh sách
days. - Sau khi xác định năm nhuận, cập nhật lại
days[1](tháng 2) = 29 hoặc 28. - Hợp lệ khi: 1 ≤ tháng ≤ 12 và 1 ≤ ngày ≤ số ngày của tháng đó.
Cách 1 — Dùng hàm kiểm tra năm nhuận (theo sách)
# date.py
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def nhuan(year):
return year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)
s = input("Nhập ngày tháng năm (dạng ngày-tháng-năm): ")
A = s.split("-")
day, month, year = int(A[0]), int(A[1]), int(A[2])
if nhuan(year):
days[1] = 29
else:
days[1] = 28
if 1 <= month <= 12 and 1 <= day <= days[month - 1]:
print(day, "-", month, "-", year, "là hợp lệ")
else:
print("Dữ liệu không hợp lệ")
Chạy thử:
Nhập 29-2-2024 → 29 - 2 - 2024 là hợp lệ (2024 là năm nhuận)
Nhập 29-2-2023 → Dữ liệu không hợp lệ (2023 không nhuận, tháng 2 chỉ 28 ngày)
Nhập 31-4-2024 → Dữ liệu không hợp lệ (tháng 4 chỉ có 30 ngày)
Cách 2 — Dùng phép toán điều kiện rút gọn
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
s = input("Nhập ngày tháng năm (dạng ngày-tháng-năm): ")
day, month, year = map(int, s.split("-"))
la_nhuan = year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)
days[1] = 29 if la_nhuan else 28
hop_le = 1 <= month <= 12 and 1 <= day <= days[month - 1]
print("Hợp lệ" if hop_le else "Không hợp lệ")
map(int, s.split("-")) ép cả ba phần tử về số nguyên cùng lúc. Biểu thức 29 if la_nhuan else 28 gán giá trị gọn trong một dòng.
⚠️ Lưu ý thi: Điều kiện năm nhuận dễ sai. Phải có cả hai vế nối bằngor:(năm % 400 == 0) or (năm % 4 == 0 and năm % 100 != 0). Ví dụ năm 1900 chia hết cho 4 nhưng chia hết cho 100 và không chia hết cho 400 → không nhuận.
Câu 4 — Luyện tập: Sắp xếp danh sách học sinh theo tên
Đề bài: Viết chương trình nhập số n, sau đó nhập danh sách họ tên (gồm họ, đệm, tên) của n học sinh. Sắp xếp tên học sinh trong lớp theo bảng chữ cái. Đưa kết quả ra màn hình.
Phân tích:
Mặc định ở Việt Nam gọi tên theo họ trước, nhưng khi xếp danh sách lớp thường ưu tiên theo tên (từ cuối cùng trong họ tên). Ta tách lấy tên làm khóa sắp xếp.
Cách 1 — Nhập danh sách rồi sắp xếp theo tên
n = int(input("Nhập số học sinh: "))
ds = []
for i in range(n):
ho_ten = input("Nhập họ tên học sinh " + str(i + 1) + ": ")
ds.append(ho_ten)
# Khóa sắp xếp là TÊN = từ cuối cùng của họ tên
ds.sort(key=lambda hoten: hoten.split()[-1])
print("Danh sách sau khi sắp xếp theo tên:")
for hoten in ds:
print(hoten)
Chạy thử với n = 3:
Nhập: Nguyễn Văn An
Nhập: Trần Thị Bình
Nhập: Lê Hoàng An
Danh sách sau khi sắp xếp theo tên:
Nguyễn Văn An
Lê Hoàng An
Trần Thị Bình
Cách 2 — Sắp xếp ưu tiên tên, rồi họ, rồi đệm
Khi nhiều học sinh trùng tên, ta cần xét tiếp họ rồi đệm. Tạo khóa là một bộ ba (tên, họ, đệm):
n = int(input("Nhập số học sinh: "))
ds = []
for i in range(n):
ds.append(input("Nhập họ tên học sinh " + str(i + 1) + ": "))
def khoa(hoten):
tu = hoten.split()
ho = tu[0]
ten = tu[-1]
dem = " ".join(tu[1:-1])
return (ten, ho, dem) # ưu tiên tên → họ → đệm
ds.sort(key=khoa)
print("Danh sách sau khi sắp xếp:")
for hoten in ds:
print(hoten)
💡 Mẹo nhớ: Khi cần sắp xếp theo nhiều tiêu chí, trả về một bộ (tuple) làm khóa. Python tự so sánh lần lượt từ trái sang phải: hết tiêu chí 1 mới xét tiêu chí 2.
Câu 5 — Vận dụng 1: Đổi giữa số thứ tự ngày và ngày tháng năm (như bảng tính điện tử)
Đề bài: Trong các phần mềm bảng tính điện tử, dữ liệu ngày tháng được coi là số ngày tính từ ngày 1/1/1900. Viết chương trình:
- a) Nhập số tự nhiên n và tính xem số đó ứng với ngày tháng năm nào.
- b) Nhập thời gian theo khuôn dạng ngày/tháng/năm và tính số ngày ứng với ngày này theo phần mềm bảng tính điện tử.
Phân tích:
Cách an toàn và chính xác nhất là dùng mô-đun datetime có sẵn của Python để cộng/trừ ngày, tránh tự xử lý năm nhuận dễ sai. Quy ước số 1 ứng với ngày 1/1/1900.
Cách 1 — Dùng mô-đun datetime
from datetime import date, timedelta
moc = date(1900, 1, 1) # số 1 ứng với ngày 1/1/1900
# a) Nhập số n → tìm ngày tháng năm
n = int(input("Nhập số thứ tự ngày n: "))
ngay = moc + timedelta(days=n - 1)
print("Số", n, "ứng với ngày:", ngay.strftime("%d/%m/%Y"))
# b) Nhập ngày/tháng/năm → tìm số thứ tự
s = input("Nhập ngày/tháng/năm (vd 1/3/2024): ")
d, m, y = map(int, s.split("/"))
ngay2 = date(y, m, d)
so_ngay = (ngay2 - moc).days + 1
print("Ngày", s, "ứng với số:", so_ngay)
Chạy thử:
Nhập n = 1 → ứng với ngày 01/01/1900
Nhập n = 32 → ứng với ngày 01/02/1900
Nhập 1/3/2024 → ứng với số 45352
Cách 2 — Tự tính bằng vòng lặp (không dùng thư viện)
Phương pháp này minh họa rõ thuật toán, dùng lại hàm kiểm tra năm nhuận ở Câu 3:
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def nhuan(year):
return year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)
# a) Số n → ngày tháng năm (đếm tiến từ 1/1/1900)
n = int(input("Nhập số thứ tự ngày n: "))
d, m, y = 1, 1, 1900
for _ in range(n - 1): # cộng dồn n-1 ngày
sn = 29 if (m == 2 and nhuan(y)) else days[m - 1]
d += 1
if d > sn: # sang tháng mới
d = 1
m += 1
if m > 12: # sang năm mới
m = 1
y += 1
print("Số", n, "ứng với ngày:", d, "/", m, "/", y)
⚠️ Lưu ý thi: Khi đề bài liên quan tính toán ngày tháng phức tạp, ưu tiên dùng datetime để khỏi sai năm nhuận. Chỉ tự code vòng lặp khi đề yêu cầu minh họa thuật toán.
Câu 6 — Vận dụng 2: Sắp xếp theo bảng chữ cái tiếng Việt
Đề bài: Mở rộng bài luyện tập: việc sắp xếp ưu tiên theo tên trước, rồi đến họ, rồi đến đệm; và phải sắp theo đúng thứ tự bảng chữ cái tiếng Việt (bao gồm cả dấu thanh): A Ă Â B C D Đ E Ê G H I K L M N O Ô Ơ P Q R S T U Ư V X Y…
Phân tích:
Thứ tự chữ cái tiếng Việt khác thứ tự mã Unicode (ví dụ "Đ" đứng sau "D" nhưng mã Unicode của "Đ" lại lớn hơn nhiều chữ khác). Vì vậy ta phải tự định nghĩa thứ tự rồi ánh xạ mỗi ký tự về số thứ tự của nó, dùng dãy số này làm khóa so sánh.
Cách 1 — Xây bảng thứ tự và chuyển xâu thành khóa số
# Bảng chữ cái tiếng Việt theo đúng thứ tự (gồm dấu thanh)
bang_chu = (
"aàảãáạăằẳẵắặâầẩẫấậ"
"bcdđeèẻẽéẹêềểễếệ"
"fghiìỉĩíịjklmn"
"oòỏõóọôồổỗốộơờởỡớợ"
"pqrstuùủũúụưừửữứựvwx"
"yỳỷỹýỵz"
)
# từ điển: mỗi ký tự → vị trí của nó trong bảng
thu_tu = {ch: i for i, ch in enumerate(bang_chu)}
def ma_hoa(s):
s = s.lower()
# ký tự không có trong bảng (vd dấu cách) cho thứ tự -1 để đứng trước
return [thu_tu.get(ch, -1) for ch in s]
def khoa(hoten):
tu = hoten.split()
ho = tu[0]
ten = tu[-1]
dem = " ".join(tu[1:-1])
# ưu tiên tên → họ → đệm, mỗi phần mã hoá theo bảng chữ cái tiếng Việt
return (ma_hoa(ten), ma_hoa(ho), ma_hoa(dem))
n = int(input("Nhập số học sinh: "))
ds = [input("Nhập họ tên học sinh " + str(i + 1) + ": ") for i in range(n)]
ds.sort(key=khoa)
print("Danh sách sắp xếp theo bảng chữ cái tiếng Việt:")
for hoten in ds:
print(hoten)
Cách 2 — Dùng locale tiếng Việt (nếu hệ thống hỗ trợ)
import locale, functools
# Đặt locale tiếng Việt; có thể không chạy được trên mọi máy
locale.setlocale(locale.LC_COLLATE, "vi_VN.UTF-8")
def lay_phan(hoten):
tu = hoten.split()
return (tu[-1], tu[0], " ".join(tu[1:-1])) # tên, họ, đệm
def so_sanh(a, b):
return locale.strcoll(str(lay_phan(a)), str(lay_phan(b)))
n = int(input("Nhập số học sinh: "))
ds = [input("Họ tên " + str(i + 1) + ": ") for i in range(n)]
ds.sort(key=functools.cmp_to_key(so_sanh))
for hoten in ds:
print(hoten)
💡 Mẹo nhớ: Sắp xếp tiếng Việt không được dùng so sánh mặc định vì mã Unicode không trùng thứ tự bảng chữ cái. Phải tự xây bảng thứ tự rồi mã hoá. Cách 1 chắc chắn chạy đúng trên mọi máy.
Câu 7 — Vận dụng 3: Kiểm tra số nguyên tố tối ưu
Đề bài: Nếu n là hợp số thì n phải có ước số nguyên tố nhỏ hơn hoặc bằng √n. Viết chương trình tối ưu hóa việc kiểm tra số nguyên tố: chỉ cần tìm ước trong các số 2, 3, 5, 7,… đến √n. Nếu không tìm thấy ước nào thì kết luận n là số nguyên tố.
Phân tích:
- Mọi hợp số n đều có một ước nguyên tố ≤ √n, nên chỉ cần kiểm tra các số từ 2 đến √n thay vì đến n − 1.
- Có thể tăng tốc thêm: sau khi loại bỏ số chẵn, chỉ xét các số lẻ 3, 5, 7, 9,… (bước nhảy 2).
Cách 1 — Duyệt đến √n
import math
def la_nguyen_to(n):
if n < 2:
return False
# duyệt từ 2 đến phần nguyên của căn n
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0: # tìm thấy ước → là hợp số
return False
return True # không có ước nào → nguyên tố
n = int(input("Nhập số n: "))
if la_nguyen_to(n):
print(n, "là số nguyên tố")
else:
print(n, "không phải số nguyên tố")
Cách 2 — Bỏ qua số chẵn, chỉ xét ước lẻ (nhanh hơn)
import math
def la_nguyen_to(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0: # loại các số chẵn > 2
return False
# chỉ xét ước lẻ 3, 5, 7, ... đến √n
for i in range(3, int(math.sqrt(n)) + 1, 2):
if n % i == 0:
return False
return True
n = int(input("Nhập số n: "))
print(n, "là số nguyên tố" if la_nguyen_to(n) else "không phải số nguyên tố")
So sánh độ phức tạp:
- Cách cũ (duyệt 2 → n−1): khoảng n phép chia.
- Cách 1 (duyệt 2 → √n): khoảng √n phép chia → nhanh hơn rất nhiều với n lớn.
- Cách 2: giảm thêm một nửa số phép chia so với Cách 1.
⚠️ Lưu ý thi: Nhớ viếtint(math.sqrt(n)) + 1trongrangeđể không bỏ sót trường hợp i bằng đúng √n (ví dụ n = 49 = 7×7, phải xét được i = 7).
🎯 Ghi nhớ: - Xử lý họ tên:split()để tách,ds[0]là họ,ds[-1]là tên,ds[1:-1]là đệm," ".join()để ghép lại. - Bài liên môn: nắm công thức gốc (P = m×g) rồi suy ra công thức cần dùng. - Năm nhuận: chia hết 400, hoặc (chia hết 4 và không chia hết 100). - Kiểm tra số nguyên tố chỉ cần duyệt đến √n; bỏ số chẵn để nhanh gấp đôi. - Sắp xếp tiếng Việt phải tự xây bảng thứ tự chữ cái, không dùng so sánh Unicode mặc định.
