Giải thuật và lập trình: §3.6. Bài tập luyện tập

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Bài tập có gợi ý lời giải

Bài 1

Nhập vào hai số nguyên dương n và k (n, k <= 100). Hãy cho biết

  1. Có bao nhiêu số nguyên dương có £ n chữ số mà tổng các chữ số đúng bằng k. Nếu có hơn 1 tỉ số thì chỉ cần thông báo có nhiều hơn 1 tỉ.
  2. Nhập vào một số p <= 1 tỉ. Cho biết nếu đem các số tìm được xếp theo thứ tự tăng dần thì số thứ p là số nào?

Gợi ý:

+ Câu a: Ta sẽ đếm số các số có đúng n chữ số mà tổng các chữ số (TCCS) bằng k, chỉ có điều các số của ta cho phép có thể bắt đầu bằng 0. Ví dụ: ta coi 0045 là số có 4 chữ số mà TCCS là 9. Gọi F[n, k] là số các số có n chữ số mà TCCS bằng k. Các số đó có dạng , với x1, x2, …xn ở đây là các chữ số 0…9 và x1 + x2 + … + xn = k. Nếu cố định x1 = t thì ta nhận thấy  lập thành một số có n - 1 chữ số mà TCCS bằng k - t. Suy ra do x1 có thể nhận các giá trị từ 0 tới 9 nên về mặt số lượng: F[n, k] = . Đây là công thức truy hồi tính F[n, k], thực ra chỉ xét những giá trị t từ 0 tới 9 và t <= k mà thôi (để tránh trường hợp k - t <0). Chú ý rằng nếu tại một bước nào đó tính ra một phần tử của F > 109 thì ta đặt lại phần tử đó là 109 + 1 để tránh bị tràn số do cộng hai số quá lớn. Kết thúc quá trình tính toán, nếu F[n, k] = 109 + 1 thì ta chỉ cần thông báo chung chung là có > 1 tỉ số.

Cơ sở quy hoạch động thì có thể đặt là:

F[1, k] = số các số có 1 chữ số mà TCCS bằng k, như vậy nếu k ³ 10 thì F[1, k] = 0 còn nếu 0 <= k <= 9 thì F[1, k] = 1.

+ Câu b: Dựa vào bảng phương án F[0..n, 0..k],

F[n - 1, k] = số các số có n - 1 CS mà TCCS bằng k = số các số có n CS, bắt đầu là 0, TCCS bằng k.

F[n - 1, k - 1] = số các số có n - 1 CS mà TCCS bằng k - 1 = số các số có n CS, bắt đầu là 1, TCCS bằng k.

F[n - 1, k - 2] = số các số có n - 1 CS mà TCCS bằng k - 2 = số các số có n CS, bắt đầu là 2, TCCS bằng k.

F[n - 1, k - 9] = số các số có n - 1 CS mà TCCS bằng k - 9 = số các số có n CS, bắt đầu là 9, TCCS bằng k.

Từ đó ta có thể biết được số thứ p (theo thứ tự tăng dần) cần tìm sẽ có chữ số đầu tiên là chữ số nào, tương tự ta sẽ tìm được chữ số thứ hai, thứ ba v.v… của số đó.

Bài 2

Cho n gói kẹo (n £ 200), mỗi gói chứa không quá 200 viên kẹo, và một số M <= 40000. Hãy chỉ ra một cách lấy ra một số các gói kẹo để được tổng số kẹo là M, hoặc thông báo rằng không thể thực hiện được việc đó.

Gợi ý: Giả sử số kẹo chứa trong gói thứ i là Ai

Gọi b[V] là số nguyên dương bé nhất thoả mãn: Có thể chọn trong số các gói kẹo từ gói 1 đến gói b[V] ra một số gói để được tổng số kẹo là V. Nếu không có phương án chọn, ta coi b[V] = . Trước tiên, khởi tạo b[0] = 0 và các b[V] = với mọi V > 0. Ta sẽ xây dựng b[V] như sau:

Để tiện nói, ta đặt k = b[V]. Vì k là bé nhất có thể, nên nếu có cách chọn trong số các gói kẹo từ gói 1 đến gói k để được số kẹo V thì chắc chắn phải chọn gói k. Mà đã chọn gói k rồi thì trong số các gói kẹo từ 1 đến k - 1, phải chọn ra được một số gói để được số kẹo là V - Ak. Tức là b[V - Ak] <= k - 1 < k. Vậy thì b[V] sẽ được tính bằng cách:

Xét tất cả các gói kẹo k có Ak <= V và thoả mãn b[V - Ak] < k, chọn ra chỉ số k bé nhất, sau đó gán b[V] := k. Đây chính là công thức truy hồi tính bảng phương án.

Sau khi đã tính b[1], b[2], …, b[M]. Nếu b[M] vẫn bằng thì có nghĩa là không có phương án chọn. Nếu không thì sẽ chọn gói p1 = b[M], tiếp theo sẽ chọn gói p2 = b[M - Ap1], rồi lại chọn gói p3 = b[M - Ap1 - Ap2]… Đến khi truy vết về tới b[0] thì thôi.

Bài 3

Cho n gói kẹo (n <= 200), mỗi gói chứa không quá 200 viên kẹo, hãy chia các gói kẹo ra làm hai nhóm sao cho số kẹo giữa hai nhóm chênh lệch nhau ít nhất.

Gợi ý:

Gọi S là tổng số kẹo và M là nửa tổng số kẹo, áp dụng cách giải như bài 2. Sau đó Tìm số nguyên dương T thoả mãn:

  • T <= M
  • Tồn tại một cách chọn ra một số gói kẹo để được tổng số kẹo là T (b[T] khác )
  • T lớn nhất có thể

Sau đó chọn ra một số gói kẹo để được T viên kẹo, các gói kẹo đó được đưa vào một nhóm, số còn lại vào nhóm thứ hai.

Bài 4

Cho một bảng A kích thước m x n, trên đó ghi các số nguyên. Một người xuất phát tại ô nào đó của cột 1, cần sang cột n (tại ô nào cũng được). Quy tắc: Từ ô A[i, j] chỉ được quyền sang một trong 3 ô A[i, j + 1]; A[i - 1, j + 1]; A[i + 1, j + 1]. Hãy tìm vị trí ô xuất phát và hành trình đi từ cột 1 sang cột n sao cho tổng các số ghi trên đường đi là lớn nhất.

Gợi ý:

Gọi B[i, j] là số điểm lớn nhất có thể có được khi tới ô A[i, j]. Rõ ràng đối với những ô ở cột 1 thì B[i, 1] = A[i, 1]:

Với những ô (i, j) ở các cột khác. Vì chỉ những ô (i, j - 1), (i - 1, j - 1), (i + 1, j - 1) là có thể sang được ô (i, j), và khi sang ô (i, j) thì số điểm được cộng thêm A[i, j] nữa. Chúng ta cần B[i, j] là số điểm lớn nhất có thể nên B[i, j] = max(B[i, j - 1], B[i - 1, j - 1], B[i + 1, j - 1]) + A[i, j]. Ta dùng công thức truy hồi này tính tất cả các B[i, j]. Cuối cùng chọn ra B[i, n] là phần tử lớn nhất trên cột n của bảng B và từ đó truy vết tìm ra đường đi nhiều điểm nhất.

Bài tập tự làm

Bài 1

Bài toán cái túi với kích thước như nêu trên là không thực tế, chẳng có siêu thị nào có <= 100 gói hàng cả. Hãy lập chương trình giải bài toán cái túi với n <= 10000; M <= 1000.

Bài 2

Xâu ký tự S gọi là xâu con của xâu ký tự T nếu có thể xoá bớt một số ký tự trong xâu T để được xâu S. Lập chương trình nhập vào hai xâu ký tự S1, S2. Tìm xâu S3 có độ dài lớn nhất là xâu con của cả S1 và S2. Ví dụ: S1 = 'abcdefghi123'; S2 = 'abc1def2ghi3' thì S3 là 'abcdefghi3'.

Bài 3

Một xâu ký tự X gọi là chứa xâu ký tự Y nếu như có thể xoá bớt một số ký tự trong xâu X để được xâu Y: Ví dụ: Xâu '1a2b3c45d' chứa xâu '12345'. Một xâu ký tự gọi là đối xứng nếu nó không thay đổi khi ta viết các ký tự trong xâu theo thứ tự ngược lại: Ví dụ: 'abcABADABAcba', 'MADAM' là các xâu đối xứng.

Nhập một xâu ký tự S có độ dài không quá 128, hãy tìm xâu ký tự T thoả mãn cả 3 điều kiện:

  1. Đối xứng
  2. Chứa xâu S
  3. Có ít ký tự nhất (có độ dài ngắn nhất)

Nếu có nhiều xâu T thoả mãn đồng thời 3 điều kiện trên thì chỉ cần cho biết một. Chẳng hạn với S = 'a_101_b' thì chọn T = 'ab_101_ba' hay T = 'ba_101_ab' đều đúng.

Ví dụ:

Bài 4

Có n loại tiền giấy: Tờ giấy bạc loại i có mệnh giá là V[i] ( n <= 20, 1 <= V[i] £ 10000). Hỏi muốn mua một món hàng giá là M thì có bao nhiêu cách trả số tiền đó bằng những loại giấy bạc đã cho (Trường hợp có > 1 tỉ cách thì chỉ cần thông báo có nhiều hơn 1 tỉ). Nếu tồn tại cách trả, cho biết cách trả phải dùng ít tờ tiền nhất.

Bài 5

Cho n quân đô-mi-nô xếp dựng đứng theo hàng ngang và được đánh số từ 1 đến n. Quân đô- mi-nô thứ i có số ghi ở ô trên là a[i] và số ghi ở ô dưới là b[i]. Xem hình vẽ:

Biết rằng 1 <= n <= 100 và 0 <= ai, bi <= 6 với "i: 1 <= i <= n. Cho phép lật ngược các quân đô-mi-nô. Khi một quân đô-mi-nô thứ i bị lật, nó sẽ có số ghi ở ô trên là b[i] và số ghi ở ô dưới là a[i].

Vấn đề đặt ra là hãy tìm cách lật các quân đô-mi-nô sao cho chênh lệch giữa tổng các số ghi ở hàng trên và tổng các số ghi ở hàng dướii là tối thiểu. Nếu có nhiều phương án lật tốt như nhau, thì chỉ ra phương án phải lật ít quân nhất.

Như ví dụ trên thì sẽ lật hai quân Đô-mi-nô thứ 5 và thứ 6. Khi đó: Tổng các số ở hàng trên = 1 + 1 + 4 + 4 + 6 + 1 = 17

Tổng các số ở hàng dưới = 6 + 3 + 1 + 1 + 0 + 6 = 17

Bài 6

Xét bảng H kích thước 4x4, các hàng và các cột được đánh chỉ số A, B, C, D. Trên 16 ô của bảng, mỗi ô ghi 1 ký tự A hoặc B hoặc C hoặc D.

Cho xâu S gồm n ký tự chỉ gồm các chữ A, B, C, D.

Xét phép co R(i): thay ký tự Si và Si+1 bởi ký tự nằm trên hàng Si, cột Si+1 của bảng H. Ví dụ: S = ABCD; áp dụng liên tiếp 3 lần R(1) sẽ được:

ABCD → ACD → BD → B.

Yêu cầu: Cho trước một ký tự XÎ{A, B, C, D}, hãy chỉ ra thứ tự thực hiện n - 1 phép co để ký tự còn lại cuối cùng trong S là X.

Bài 7

Cho N số tự nhiên A1, A2, …, AN. Biết rằng 1 <= N <= 200 và 0 <= Ai <= 200. Ban đầu các số được đặt liên tiếp theo đúng thứ tự cách nhau bởi dấu "?": A1 ? A2 ? … ? AN. Yêu cầu: Cho trước số nguyên K, hãy tìm cách thay các dấu "?" bằng dấu cộng hay dấu trừ để được một biểu thức số học cho giá trị là K. Biết rằng 1 <= N <= 200 và 0 <= Ai <= 100.

Ví dụ: Ban đầu 1 ? 2 ? 3 ? 4 và K = 0 sẽ cho kết quả 1 - 2 - 3 + 4.

Bài 8

Dãy Catalan là một dãy số tự nhiên bắt đầu là 0, kết thúc là 0, hai phần tử liên tiếp hơn kém nhau 1 đơn vị. Hãy lập chương trình nhập vào số nguyên dương n lẻ và một số nguyên dương p. Cho biết rằng nếu như ta đem tất cả các dãy Catalan độ dài n xếp theo thứ tự từ điển thì dãy thứ p là dãy nào.

Một bài toán quy hoạch động có thể có nhiều cách tiếp cận khác nhau, chọn cách nào là tuỳ theo yêu cầu bài toán sao cho dễ dàng cài đặt nhất. Phương pháp này thường không khó khăn trong việc tính bảng phương án, không khó khăn trong việc tìm cơ sở quy hoạch động, mà khó khăn chính là nhìn nhận ra bài toán quy hoạch động tìm ra công thức truy hồi giải nó, công việc này đòi hỏi sự nhanh nhạy, khôn khéo, mà chỉ từ sự rèn luyện mới có thể có được. Hãy đọc lại §1. Công thức truy hồi để tìm hiểu kỹ các phương pháp thông dụng khi cài đặt một chương trình giải công thức truy hồi.

Nguồn: Giáo trình Giải thuật và Lập trình - Lê Minh Hoàng - Đại học sư phạm Hà Nội
« Trước: §3.5. Phép nhân tổ hợp dãy ma trận
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!