You are on page 1of 90

THPT CHUYÊN BẮC GIANG

MỞ ĐẦU

Duyệt các cấu hình tổ hợp và ứng dụng Trang 1


THPT CHUYÊN BẮC GIANG

PHẦN 1. LÝ THUYẾT TỔ HỢP


I. SƠ LƯỢC VỀ TỔ HỢP
1. Khái niệm
Tổ hợp như là một lĩnh vực của toán học rời rạc, xuất hiện vào đầu thế kỉ 17.
Lý thuyết tổ hợp được áp dụng trong nhiều lĩnh vực khác nhau: lý thuyết số, hình
học hữu hạn, biểu diễn nhóm, đại số không giao hoán, thống kê xác xuất, …
Lý thuyết tổ hợp gắn liền với việc nghiên cứu sự phân bố các phần tử vào các tập
hợp. Các phần tử là hữu hạn và việc phân bố chúng phải thỏa mãn những điều kiện
nào đó tùy theo yêu cầu của công việc (bài toán).
Mỗi cách phân bố như thế được gọi là một cấu hình tổ hợp (một bộ các phần tử
nào đó).

2. Các bài toán thường gặp


a) Bài toán đếm: “Có bao nhiêu cấu hình thỏa mãn điều kiện đã nêu?”
Dùng để đánh giá hiệu quả công việc như: tính xác xuất của 1 sự kiện, độ phức
tạp của một thuật toán.
b) Bài toán liệt kê: “Liệt kê tất cả các cấu hình tổ hợp có thể được” (các phương
án)
Bài toán liệt kê làm nền, làm cơ sở cho nhiều bài toán khác.
c) Bài toán tối ưu: “Chỉ ra một hoặc một số cấu hình tốt nhất theo một nghĩa nào
đó” (có giá lớn nhất hay có giá nhỏ nhất), là bài toán phổ biến trong cuộc sống
d) Bài toán tồn tại: “Có tồn tại hay không tồn tại cấu hình thỏa mãn điều kiện
nào đó?”
Ví dụ về bài toán hình lục giác thần bí chẳng hạn

II. NHẮC LẠI LÝ THUYẾT TẬP HỢP

1. Các khái niệm và ký hiệu


– Tập hợp ký hiệu bằng chữ cái lớn A, B, … , X, Y, …
– Các phần tử ký hiệu bằng chữ cái nhỏ: a, b, x, y, …
– Nếu x là phần tử của tập X ta viết x X
– Nếu x không là phần tử của tập X ta viết x  X

Duyệt các cấu hình tổ hợp và ứng dụng Trang 2


THPT CHUYÊN BẮC GIANG

– Tập A là tập con của tập B   x  A x  B, kí hiệu A  B


– Nếu đồng thời A  B và B  A thì A = B
– Số các phần tử của tập hợp A, ký hiệu là N(A) hoặc |A| (còn gọi là lực lượng của
tập A)
– Một tập gồm n phần tử gọi là một n-tập
– Tập rỗng là tập không có phần tử nào, ký hiệu là 

2. Các phép toán trên tập hợp


– Giao của 2 tập hợp A và B kí hiệu là A  B: A  B = {x | x  A và x  B}
– Hợp của 2 tập hợp A và B kí hiệu là A  B: A  B = {x | x  A hoặc x  B}
– Hiệu của 2 tập hợp A và B kí hiệu là A\B: A\B = {x | x  A và x  B}
– Phần bù của A trong X kí hiệu là A : A = {x |x  X và x  A}
– Tích đề các của 2 tập hợp A và B kí hiệu A x B hoặc A.B
– A x B = {(a, b)| a  A và b  B}

III. CÁC NGUYÊN LÝ CƠ BẢN

1. Nguyên lí cộng
Ví dụ 1: Có 8 quyển sách và 6 quyển vở khác nhau. Hỏi có bao nhiêu cách chọn
1 quyển trong các quyển trên?
* Hd:
 Có 8 cách chọn ra 1 quyển sách
 Có 6 cách chọn ra 1 quyển vở
Với mỗi cách chọn 1 quyển sách không trùng với cách chọn bất kì một quyển vở
nào và ngược lại với mỗi cách chọn 1 quyển vở không trùng với cách chọn bất kì một
quyển sách nào
=>có 8 + 6 = 14 cách chọn 1 quyển trong số các quyển sách và vở đã cho
* Đơn giản
Giả sử có m cách chọn đối tượng x, có n cách chọn đối tượng y và mỗi cách
chọn đối tượng x không trùng với bất kỳ cách chọn đối tượng y nào và ngược lại mỗi
cách chọn đối tượng y không trùng với bất kỳ cách chọn đối tượng x nào thì sẽ có
m+n cách chọn 1 trong các đối tượng đã cho
* Nguyên lí cộng tổng quát

Duyệt các cấu hình tổ hợp và ứng dụng Trang 3


THPT CHUYÊN BẮC GIANG

 Nếu có m1 cách chọn đối tượng x1


 Có m2 cách chọn đối tượng x2
 …………
 Có mn cách chọn đối tượng xn
Và mỗi cách chọn đối tượng xi không trùng với bất kì cách chọn đối tượng xj nào
nếu i <> j (i,j = 1,2, …,n)
Thì có m1 + m2 +…+ mn cách chọn 1 trong các đối tượng đã cho
Ví dụ 2: Cho 2 tập hợp A và B, biết |A| = m và |B| = n và AB= . Hỏi
|AB|=?
Ví dụ 3: Sau khi thực hiện xong các câu lệnh sau, giá trị của K bằng bao nhiêu?
n1 := 10; n2 := 20; n3 := 30;
k:=0;
for i1:=1 to n1 do k := k+1;
for i2:=1 to n2 do k := k+1;
for i3:=1 to n3 do k := k+1;
Ví dụ 4: Từ các chữ số 1, 2, 3 có thể lập được bao nhiêu số khác nhau, các chữ
số trong mỗi số khác nhau?
* Hd VD4: Vì các số trong một số hạng là khác nhau nên số cần lập từ các số 1,
2, 3 chỉ có thể là số có 1 chữ số, có 2 chữ số, có 3 chữ số.
Gọi x1 là số cách chọn số có 1 chữ số
x2 là số cách chọn số có 2 chữ số
x3 là số cách chọn số có 3 chữ số
x1 = 3 (các số 1, 2, 3)
x2 = 6 (các số 12, 13, 21, 23,31, 32)
x3 = 6 (các số 123, 132, 213, 231, 321,312)
và với mỗi cách chọn số có 1 chữ số không trùng với cách chọn số có 2 chữ số
và 3 chữ số và ngược lại
Theo nguyên lí cộng có 3+6+6 = 15 số khác nhau thỏa mãn đầu bài

2. Nguyên lí nhân
Ví dụ 5: Để đi từ TP A đến TP B có 3 cách chọn phương tiện đi lại (ôtô, tàu hỏa,
máy bay), để đi từ TP B đến TP C có 4 cách chọn phương tiện đi lại (ôtô, tàu hỏa, tàu

Duyệt các cấu hình tổ hợp và ứng dụng Trang 4


THPT CHUYÊN BẮC GIANG

thủy, máy bay). Hỏi có bao nhiêu cách chọn bộ phương tiện để đi từ TP A đến TP C
phải đi qua TP B?
* Hd:
Gọi x1 là phương tiện đi từ A đến B, x2 là phương tiện đi từ B đến C. Khi đó: Có
3 cách chọn đối tượng x1, với mỗi cách chọn đối tượng x1 có 4 cách chọn đối tượng x2
=>Số cách chọn bộ phương tiện để đi từ A  B  C đúng bằng số cách chọn
bộ 2 thành phần (x1, x2)
= 3 x 4 = 12 cách
* Nguyên lí nhân tổng quát
Có m1 cách chọn đối tượng x1
với mỗi cách chọn đối tượng x1, có m2 cách chọn đối tượng x2
với mỗi cách chọn bộ đối tượng (x1, x2), có m3 cách chọn đối tượng x3
…..
với mỗi cách chọn bộ đối tượng (x1, x2,…, xn-1), có mn cách chọn đối tượng xn
=> thì có m1 x m2 x m3 x … x mn cách chọn 1 bộ có n thành phần (x1,x2…xn)
Ví dụ 6: Một lớp có 34 học sinh. Hỏi có bao nhiêu cách chọn ra một ban cán sự
lớp gồm 1 lớp trưởng, 1 lớp phó, 1 bí thư.
Biết rằng mỗi học sinh được tham gia vào ban cán sự chỉ được nhận 1 nhiệm vụ
và bất kì học sịnh nào cũng có thể tham gia ban cán sự?
GV đưa kq = 34 X 33 x 32 = 35904
Ví dụ 7: Có bao nhiêu số có 3 chữ số khác nhau lấy từ tập {0,1,2,3,4,5,6,7,8,9}?
GV đưa kq = 10 x 9 x 8 = 720
Ví dụ 8: Cho |A| = m và |B| = n chứng minh |AxB| = m*n
Ví dụ 9: Sau khi thực hiện xong các câu lệnh sau, giá trị của K bằng bao nhiêu?
n1 := 10; n2 := 20; n3 := 30;
k:=0;
for i1:=1 to n1 do k := k+1
for i2:=1 to n2 do k := k+1
for i3:=1 to n3 do k:=k+1;
Ví dụ 10: Có bao nhiêu xâu nhị phân độ dài 8?
Ví dụ 11: Có bao nhiêu xâu nhị phân độ dài n?

Duyệt các cấu hình tổ hợp và ứng dụng Trang 5


THPT CHUYÊN BẮC GIANG

GV đưa kq= 2n
Ví dụ 12: Có bao nhiêu tập con của một tập hợp có n phần tử A={a1, a2, .., an}?
* Hd ví dụ 12:
Xét xâu nhị phân có n bít x1,x2, … ,xn
Sự tương ứng 1-1 giữa 1 tập con của tập hợp A với 1 dãy nhị phân độ dài n.
Bởi vì:
nếu bít xi = 1 tương ứng với việc có mặt phần tử ai trong tập con
nếu bít xi = 0 tương ứng với việc không có mặt phần tử ai trong tập con
Do đó, số tập con của một tập hợp có n phần tử đúng bằng số xâu nhị phân độ
dài n = 2n

3. Nguyên lí bù trừ
Nếu một nhiệm vụ có 2 công việc, 2 công việc có thể thực hiện đồng thời
Thì số cách thực hiện nhiệm vụ gồm 2 công việc đó bằng tổng số cách làm mỗi
công việc trừ đi số cách làm đồng thời cả 2 công việc.
Ví dụ 13: |A| = m và |B| = n
|A+B| = m + n - |A  B|
Ví dụ 14: Có bao nhiêu xâu nhị phân độ dài 8 thỏa mãn có bít đầu bằng 1 hoặc
có 2 bít cuối là 00?
* Hd ví dụ 14:
+ Xâu nhị phân độ dài 8 có bít đầu bằng 1 là 1 bộ có dạng: 1x2x3x4x5x6x7x8, với
xi=(0,1) ==> có 27 = 128 xâu thỏa mãn
+ Xâu nhị phân độ dài 8 có bít kết thúc bằng 00 là 1 bộ có dạng: x 1x2x3x4x5x600
=> có 26 = 62 xâu thỏa mãn
+ Xâu nhị phân độ dài 8 có bít vừa bắt đầu bằng 1, vừa kết thúc bằng 00 là 1 bộ
có dạng: 1x2x3x4x5x600, ==> có 25 = 32 xâu thỏa mãn
Vậy số xâu thỏa mãn đề bài là 128 + 64 – 32 = 160.
* Trường hợp đơn giản: Cho 2 tập hợp A và B (chưa biết có rời nhau hay
không).
Khi đó: N(A  B) = N(A) + N(B) - N(A  B)
* Trường hợp tổng quát: Cho m tập hữu hạn A1, A2, ..,Am. Khi đó:
N(A1A2A3...Am) = N1-N2+N3-....+(-1)m-1Nm

Duyệt các cấu hình tổ hợp và ứng dụng Trang 6


THPT CHUYÊN BẮC GIANG

Trong đó Nk là tổng phần tử của tất cả các giao của k_tập (tập con k phần tử) lấy
từ m-tập đã cho, với k=2,3,4, ..., m-1
Đặc biệt:
N1 = N(A1) + N(A2) + ...+ N(Am)
Nm = N(A1A2 ...Am)
Ví dụ 17: Cho 3 tập hợp A, B, C. biết:
A = {0,1,2,7,11,14,25}
B = {-5,-4,0,2,7,13,15,16,19}
C = {-5,-2,2,7,13,14,16,20,21}
Hỏi N(A  B  C) = ?
* Hd: Ta có N(A) = 7; N(B)=9; N(C)=9;
N1=7+9+9 =25
N2=N(AB)+N(AC)+N(BC) = 3 + 3+5=11
N3 = N(ABC) = 2
Theo nguyên lí bù trừ ta có:
N(A  B  C)=N1-N2+N3 = 25-11+2=16
Ví dụ 18: Hỏi trong tập X={1,2,...,10000} có bao nhiêu số không chia hết cho
bất cứ số nào trong các số 3,4,7?
* Bài tập tham khảo
BT1: Từ các số 0, 1, 2, .., 6 lập được bao nhiêu số tự nhiên chẵn có 3 chữ số?
BT2: Có bao nhiêu số có 2 chữ số mà chữ số hang chục khác 0 và số chẵn?
Bt3: Có bao nhiêu số tự nhiên có 5 chữ số trong đó số cách đều 2 số ở giữa là
giống nhau? (vd 32123)
BT4: Có bao nhiêu số tự nhiên có 6 chữ số chia hết cho 5?

4. Nguyên lí Dirichlê
“Cần nhốt 6 thỏ vào 5 lồng thì ắt phải có 1 lồng chứa ít nhất 2 thỏ”
* TQ: “Có n đồ vật được đặt vào k hộp, ắt phải có ít nhất 1 hộp chứa ít nhất [n /
k] đồ vật”
Ví dụ 15: Có 100 người. Hãy tìm xem có ít nhất bao nhiêu người có cùng tháng
sinh?
TL: [100/12] = 9

Duyệt các cấu hình tổ hợp và ứng dụng Trang 7


THPT CHUYÊN BẮC GIANG

Ví dụ 16: Trong số 367 người, có bao nhiêu người có cùng ngày sinh?
Tl: 1

IV. MỘT SỐ CẤU HÌNH TỔ HỢP THƯỜNG GẶP

1. Hoán vị
a. Định nghĩa: Một hoán vị của n phần tử (n >= 1) là một cách sắp thứ tự n
phần tử đó.
Ví dụ1: Cho n=3 và các phần tử là {1,2,3} thì các hoán vị của 3 phần tử trên là:
(1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1)
Ví dụ 2: Có 5 người xếp hàng, có chiều cao bằng nhau. Hỏi có bao nhiêu cách
xếp 5 người đó thành hàng?
*Tổng quát: Cho tập hợp A có n phần tử a1, a2, …,an. Một hoán vị của n phần tử
của tập hợp A là một bộ có n thành phần (x1, x2, …,xn), xi  A và xi <>xj 
i,j=1,2,..,n, i<> j

b. Số hoán vị của n phần tử kí hiệu là Pn


Ta có: Pn = n! = 1.2.3. … .n
*Chứng minh: Pn = n!
GV yêu cầu HS chứng minh
Gợi ý: Số hoán vị của n phần tử đúng bằng số bộ (x1, x2, …,xn), xi  A và xi<>xj
với i <> j; ( i,j=1,2,..,n)

2. Chỉnh hợp lặp chập k của n phần tử


a. Định nghĩa: Một chỉnh hợp lặp chập k của n phần tử là một bộ có thứ tự
gồm k thành phần lấy từ n phần tử đã cho, các thành phần có thể được lặp lại.
(n>1, k>0)
Ví dụ 3: n=3, A = {1,2,3}. => các chỉnh hợp lặp chập 2 của 3 phần tử trên: (1,1),
(1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3)
*Tổng quát: Cho tập hợp A có n phần tử a1, a2…,an.
Một chỉnh hợp lặp chập k của n phần tử của tập hợp A là một bộ gồm k thành
phần (x1, x2, …,xk), xi  A, i=1,2,..,k

b. Số chỉnh hợp lặp chập k của n phần tử kí hiệu là A kn : A kn = nk


*Chứng minh: A kn = nk

Duyệt các cấu hình tổ hợp và ứng dụng Trang 8


THPT CHUYÊN BẮC GIANG

GV yêu cầu HS chứng minh dựa trên nguyên lý nhân


Ví dụ 4: Mã khóa số có 3 chữ số lấy từ tập có 10 phần tử ={0,1,2,3,4,5,6,7,8,9}.
Hỏi có bao nhiêu trạng thái của mã số?
GV hướng dẫn HS:
Mã khóa số là bộ có 3 thành phần (x1,x2,x3), với xi  A, i=1,2,3
Vậy mỗi trạng thái của mã số là một chỉnh hợp lặp chập 3 của 10 phần tử của tập
hợp A. => số trạng thái của mã số bằng số chỉnh hợp lặp chập 3 của 10 phần tử = A103
= 103 = 1000

3. Chỉnh hợp không lặp chập k của n phần tử


a) Định nghĩa: Một chỉnh hợp không lặp chập k của n phần tử là một bộ có thứ tự
gồm k thành phần khác nhau lấy từ n phần tử đã cho (n>1, k>0, n>k).
Ví dụ 5: n=3, A = {1,2,3}. => các chỉnh hợp không lặp chập 2 của 3 phần tử
trên: (1,2), (1,3), (2,1), (2,3), (3,1), (3,2)
Ví dụ 6: Cho n=3, k=2 và A = {x, a, y}. => các chỉnh hợp không lặp chập 2 của
3 phần tử trên: (x,a), (x,y), (a,x), (a,y), (y,x), (y,a)
*Tổng quát: Cho tập hợp A có n phần tử a1, a2, …,an.
Một chỉnh hợp không lặp chập k của n phần tử của tập hợp A là một bộ gồm k
thành phần (x1, x2, …,xk), xi  A, i,j = 1,2, .., k và xi <> xj nếu i<>j
b)Số chỉnh hợp không lặp chập k của n phần tử kí hiệu là A kn
n!
A kn = n.(n-1). ... .(n-k+1) =
(n  k)!
n!
*Chứng minh: A kn =n.(n-1). ... .(n-k+1)=
(n  k)!
GV yêu cầu HS chứng minh dựa trên nguyên lý nhân

4. Tổ hợp k của n phần tử


a) Định nghĩa: Một tổ hợp chập k của n phần tử là một bộ không kể thứ tự gồm k
thành phần khác nhau lấy từ n phần tử đã cho, hai thành phần bất kì trong bộ đó phải
khác nhau. (n>1, k>0, n>k)
Nói cách khác, một tổ hợp chập k của n phần tử là một tập con k phần tử của nó.
Ví dụ 7: Cho A = {1,2,3,4}. n=4, k=3. => các tổ hợp chập 3 của 4 phần tử là:
(1,2,3), (1,2,4), (1,3,4), (2,3,4)
*Tổng quát: Cho tập hợp A có n phần tử a1, a2, …,an.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 9


THPT CHUYÊN BẮC GIANG

Một tổ hợp chập k của n phần tử của tập hợp A là một tập con gồm k thành phần
(x1, x2, …,xk), xi  A, i= 1,2, .., k và x1 < x2 < x3 < ... , xk
n!
b)Số tổ hợp chập k của n phần tử kí hiệu là C kn : C kn =
k!(n  k)!
Tư tưởng: Xây dựng số chỉnh hợp không lặp chập k của n phần tử bằng phương
pháp phân hoạch.
B1: Từ tập n phần tử đã cho ta lấy ra tất cả các tập con k phần tử (x1,x2…xk)
==> Có C kn cách chọn ra 1 tập con k phần tử từ tập n phần tử.
B2: Với mỗi tập con k phần tử, ta sắp thứ tự k phần tử của tập con đó ==> có k!
cách sắp thứ tự.
Mỗi cách sắp thứ tự của k phần tử đó là một chỉnh hợp không lặp chập k của n
phần tử đã cho.
=> theo nguyên lí nhân có A kn = C kn . k!
Thật vậy:
 Trước tiên, ta xét tập các chỉnh hợp không lặp chập k của n phần tử.
 Ta chia tập đó thành các lớp sao cho các chỉnh hợp không lặp chập k của n
phần tử trong cùng một lớp giống nhau về các phần tử nhưng khác nhau ở thứ tự
sắp xếp (Tức là, các chỉnh hợp không lặp chập k của n của 1 lớp là các hoán vị
của cùng 1 tập con).
- Ví dụ: Tập các chỉnh hợp không lặp chập 3 của. 4 phần tử {1,2,3,4} được chia
thành 4 lớp như sau:
Lớp 1: (1,2,3), (1,3,2), (2,1,3),(2,3,1),(3,1,2),(3,2,1)
Lớp 2: (1,2,4), (1,4,2), (2,1,4),(2,4,1),(4,1,2),(4,2,1)
Lớp 3: (1,3,4), (1,4,3),(3,1,4),(3,4,1),(4,1,3),(4,3,1)
Lớp 4: (2,3,4), (2,4,3),(3,2,4),(3,4,2),(4,2,3),(4,3,2)
- Ta nhận số lớp đúng bằng số tập con k phần tử của tập n phần tử đã cho (số tổ
hợp chập k của n). Với mỗi lớp lại có k! chỉnh hợp không lặp chập k của n phần tử.
Nếu ta kí hiệu C kn là số tổ hợp chập k của n thì theo nguyên lí nhân ta có:
A kn n!
A kn = C kn . k!, => C kn = = (ĐPCM)
k! k!(n  k)!
Ví dụ 8: Có n đội bóng thi đấu vòng tròn sao cho cứ 2 đội bất kì gặp nhau đúng
một trận. Hỏi phải tổ chức bao nhiêu trận đấu?

Duyệt các cấu hình tổ hợp và ứng dụng Trang 10


THPT CHUYÊN BẮC GIANG

* Hd ví dụ 8:
Cứ 2 đội thì có 1 trận đấu. Suy ra số trận đấu bằng số cách chọn 2 đội từ n đội,
n.(n  1)
bằng C n2 =
2
Ví dụ 9: Hỏi có bao nhiêu giao điểm của các đường chéo của một đa giác lồi n
đỉnh (n > 4) nằm trong đa giác. Giả thiết rằng không có ba đường chéo nào đồng quy
tại điểm ở trong đa giác.
* Hd ví dụ 9:
Cứ 4 đỉnh của đa giác, có một giao điểm của 2 đường chéo nằm trong đa giác.
Vậy số giao điểm của các đường chéo nằm trong đa giác đúng bằng số cách lấy
ra 4 đỉnh từ tập n đỉnh của đa giác lồi đã cho.
n! n.(n  1).(n  2)(n  3)
=> Số giao điểm cần đếm là: C n4 = =
4!.(n  4)! 24
c) Một vài tính chất quan trọng của các hệ số tổ hợp
+ Tính đối xứng: C kn = C n nk
+ Điều kiện đầu: C n1 = C nn =1
+ Công thức đệ quy: C kn = C kn 11 + C n k1 với n.k>0
n
+ Tổng tất cả các tập con của tập n phần tử C
k 0
k
n = 2n

+ Công thức nhị thức Niutơn


(x+y)n = C n0 xn + C n1 xn-1.y + ... + C n n1 x.yn-1+ C nn yn

Duyệt các cấu hình tổ hợp và ứng dụng Trang 11


THPT CHUYÊN BẮC GIANG

PHẦN 2. PHƯƠNG PHÁP SINH


I. Khái niệm
Phương pháp sinh được sử dụng trong bài toán liệt kê, ví dụ như người ta cần
liệt kê tổ hợp chập k của n phần tử hay hoán vị của một tập số, hay khi người cần làm
một bài toán mà không thể áp dụng các phương pháp thông minh như quy hoạch
động, chia để trị thì phương pháp liệt kê để xét vét cạn là sự lựa chọn cuối cùng.
Phương pháp sinh là phương pháp từ cấu hình đầu tiên ta sinh ra các cấu hình tiếp
theo. Không phải bài nào cũng có thể làm theo phương pháp sinh, yêu cầu của bài
toán để có thể làm theo phương pháp sinh là:
- Thứ nhất phải xác định được cấu hình đầu và cấu hình cuối
- Thứ hai phải xác định được cấu hình tiếp theo bằng 1 công thức nhất định
Việc xác định cấu hình đầu tiên và cấu hình cuối cùng là do yêu cầu đặt ra của
từng bài toán và do cách xác định của từng người lập trình.
Yêu cầu quan trọng hơn khi sử dụng phương pháp sinh là làm sao từ cấu hình
đang có ta có thể đưa ra được cấu hình tiếp theo hoặc là khẳng định đó là cấu hình
cuối cùng. Ta tạm gọi bài toán từ cấu hình ban đầu sinh ra cấu hình tiếp theo có thủ
tục là sinh_kế_tiếp. Khi đó bài toán sử dụng phương pháp sinh được viết như sau:
Procedure Generate;
Begin
<Xây dựng cấu hình ban đầu>;
Stop := False;
While not Stop Do
Begin
<Đưa ra cấu hình đang có>;
sinh_kế_tiếp;
End;
End;
Trong thủ tục sinh_kế_tiếp, nếu cấu hình đang có là cuối cùng thì thủ tục này
cần gán cho biến Stop giá trị True, ngược lại thủ tục này sẽ xây dựng cấu hình kế tiếp
của cấu hình đang có trong thứ tự đã xác định.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 12


THPT CHUYÊN BẮC GIANG

II. Áp dụng phương pháp sinh vào giải một số bài toán

1. Bài toán 1: Liệt kê tất cả các dãy nhị phân có độ dài N.


Bài toán có thể được phát biểu như sau: Cho N là một số nguyên dương, hãy chỉ
ra tất cả các dãy b1, b2, …, bN với bi {0; 1}, (1  i  N).
Ví dụ với N = 3 ta có các dãy đó là:
1. 0 0 0 5. 1 0 0
2. 0 0 1 6. 1 0 1
3. 0 1 0 7. 1 1 0
4. 0 1 1 8. 1 1 1
Phân tích bài toán: Ta có thể thấy ngay dãy đầu tiên là 0 0 0 …0 (dãy toàn số 0)
và dãy cuối cùng là 1 1 1 … 1 (dãy toàn số 1).
Từ cấu hình đang có thì cấu hình tiếp theo được xây dựng bằng cách cộng thêm
1 (cộng nhị phân) nếu ta cách biểu diễn cấu hình là biểu diễn nhị phân của một số
nguyên. Ví dụ từ cấu hình 0 1 0 (2) thì cấu hình tiếp theo là 0 1 1 (3).
Từ cấu hình đang có b1, b2, …, bN ta có thể xây dựng cấu hình tiếp theo với qui
tắc sau
- Tìm i đầu tiên (theo thứ tự i = n, n-1, .. 1) thoã mãn bi = 0;
- Gán lại bi = 1 và bj = 0 với tất cả j > i. Dãy mới thu được sẽ là dãy cần tìm.
Ví dụ: Xét dãy nhị phân độ dài 10, b = 1001001111.
+ Ta tìm được i đầu tiên = 5.
+ Bây giờ ta gán b5 =1 và b6, b7, b8, b9, b10 = 0  Xâu nhị phân kế tiếp là
1001010000 (tương ứng với 1001001111 (591) + 1 = 1001010000 (592))
Thuật toán sinh kế tiếp cho bài toán này được diễn tả như sau:
Procedure Next_Bit_String;
Begin
i := n;
while bi = 1 do
Begin
bi := 0;
i := i -1;
End;
bi := 1;
End;
Chương trình của bài toán:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 13


THPT CHUYÊN BẮC GIANG

Program Bai1;
var n, i: integer;
b: Array[1..20] of 0..1;
count : word;
stop : boolean;
Procedure init;
var i: integer;
Begin
Write('Do dai day nhi phan = '); readln(n);
for i := 1 to n do b[i] := 0;
stop := false;
count := 0;
End;
Procedure Next_Bit_String;
Var i: integer;
Begin
i:=n;
while (i>=1) and (b[i]=1) do
Begin
b[i] := 0;
i := i-1;
End;
if i < 1 then stop := True Else b[i] := 1;
End;
BEGIN
init;
While not (stop) do
Begin
count := count + 1;
Write(Count:5);
For i := 1 to n do Write(b[i]:2); writeln;
Next_Bit_String;
End;
Write('Bam phim Enter de thoat khoi Chuong trinh '); Readln;
END.

2. Bài toán 2: Liệt kê các tập con m phần tử của tập n phần tử.
Bài toán có thể phát biểu như sau: Cho tập hợp Cho X = {1, 2, 3, .. , n}. Hãy liệt
kê các tập con có m phần tử của X. Ví dụ: X= {1, 2, 3, 4, 5}, m= 3. Các tập con 3
phần tử của X là:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 14


THPT CHUYÊN BẮC GIANG

1. {1, 2, 3} 2. {1, 2, 4} 3. {1, 2, 5} 4. {1, 3, 4} 5. {1, 3, 5}


6. {1, 4, 5} 7. {2, 3, 4} 8. {2, 3, 5} 9. {2, 4, 5} 10. {3, 4, 5}
Phân tích bài toán:
Mỗi tập con m phần tử của X có thể biểu diễn bởi bộ có thứ tự gồm m thành
phần a = {a1, a2, .., am} thoả mãn 1  a1 < a2 < … am  n.
Ta thấy cấu hình đầu tiên là {1, 2, 3, …, m} và cấu hình cuối cùng là {n-m+1, n-
m+2, …, n}
Từ cấu hình đang có {a1, a2, .., am } ta tìm cấu hình tiếp theo bằng cách:
- Tìm từ bên phải dãy a1, a2, …, a3 phần tử ai  n-m+i;
- Thay ai bởi ai+1;
- Thay aj bởi ai + j – i với j = i+1, i+2, …, m.
Ví dụ: Với n = 6 và m = 4. Giả sử tập con đang có là {1, 2, 5, 6}, cần xây dựng
tập con kế tiếp.
+ Ta tìm được i = 2
+ Thay a2 = 3
+ Thay a3=4, a4= 5
 ta được tập con kế tiếp là {1, 3, 4, 5}
Thuật toán sinh kế tiếp cho bài toàn này được diễn tả như sau:
Procedure Next_Combination;
Begin
i := m;
while ai = n – m + i do i := i - 1;
ai := ai + 1;
for j := i + 1 to n do aj := ai + j - i;
End;
Chương trình của bài toán được diễn tả như sau:
Program tap_con;
Var n, m,i : integer;
a: Array[1..20] of integer;
count: longint;
stop : boolean;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 15


THPT CHUYÊN BẮC GIANG

Procedure init;
Var i : integer;
Begin
Write('Moi nhap N '); Readln(n);
Write('Moi nhap M '); Readln(m);
For i:= 1 to m do a[i] := i;
stop := false;
count := 0;
End;
Procedure Next_Combination;
Var i, j: integer;
Begin
i := m;
while (i>0) and (a[i] = n-m+i) do i := i-1;
if i = 0 then stop := True
else
begin
a[i] := a[i]+1;
for j := i+1 to m do a[j] := a[i]+j-i;
end;
End;
BEGIN
init;
while not stop do
begin
count := count+1;
Write(count:5);
for i := 1 to m do write(a[i]:3); writeln;
Next_Combination;
end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 16


THPT CHUYÊN BẮC GIANG

Write('Bam Enter de ket thuc '); Readln


End.

3. Bài toán 3: Liệt kê các hoán vị của tập n phần tử.


Bài toán có thể phát biểu như sau: Cho X = {1, 2, 3, .. , n}. Hãy liệt kê các hoán
vị từ n phần tử của X. Ví dụ với n = 3 thì các hoán vị của nó là:

1. (1, 2, 3) 4. (2, 3, 1)
2. (1, 3, 2) 5. (3, 1, 2)
3. (2, 1, 3) 6. (3, 2, 1)
Phân tích bài toán:
Ta thấy ngay theo thứ tự trên thì cầu hình đầu tiên là: (1, 2, 3, . . n) và cấu hình
cuối cùng là (n, n-1, ..., 2, 1).
Cần xây dựng thuật toán để từ cấu hình đang có là (a1, a2, …, an) ta tìm được cấu
hình tiếp theo. Từ cấu hình đang có {a1, a2, …, an} ta xây dựng cấu hình tiếp theo
bằng qui tắc:
– Tìm j đầu tiên thoả mãn aj<aj+1 (j giảm từ n, n-1, …, 1);
– Tìm ak là số nhỏ nhất và ak>aj trong các số aj+1, aj+2, …, an;
– Đỗi chỗ aj với ak;
– Đảo ngược đoạn từ aj+1 đến an.
Ví dụ với n = 6, cấu hình đang có là (3, 6, 2, 5, 4, 1)
+ Ta tìm được j = 3
+ Ta tìm được k = 5
+ Hoán vị a3 với a6 ta được (3, 6, 4, 5, 2, 1)
+ Đảo ngược đoạn a4, a5, a6 ta được (3, 6, 4, 1, 2, 5)
 Cấu hình tiếp theo là (3, 6, 4, 1, 2, 5)
Chương trình của bài toán là:
Program hoan_vi;
Var a:array[1..100] of integer;
n,i: integer;
count: longint;
stop : Boolean;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 17


THPT CHUYÊN BẮC GIANG

Procedure init;
var i: integer;
Begin
Write('Moi nhap vao N '); Readln(n);
For i := 1 to N do a[i]:=i;
Stop := False;
Count := 0;
end;
Procedure next_Permution;
Var j,k,l,m:integer;
tg: integer;
Begin
j := n-1;
while (j >0) and (a[j] > a[j+1]) do dec(j);
if j = 0 then stop := True else
begin
k := n;
while a[j] > a[k] do dec(k);
tg := a[j];
a[j] := a[k];
a[k] := tg;
l := n;
m := j+1;
while l > m do
begin
tg := a[l];
a[l] := a[m];
a[m] := tg;
dec(l);
inc(m);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 18


THPT CHUYÊN BẮC GIANG

end;
end;
end;
BEGIN
init;
while not stop do
begin
inc(count); write(count,'. ');
For i := 1 to N do write(a[i]:3); writeln;
next_permution;
end;
Write('Bam Enter de ket thuc '); Readln;
END.

4. Bài toán 4: Phân tích số nguyên dương N thành tổng các số nguyên không âm.
Bài toán được phát biểu như sau: Cho một số nguyên dương N. Hãy liệt kê các
cách phân tích N thành tổng các số nguyên không âm. Ví dụ với N = 4, ta có thể phân
tích thành:
1. 4
2. 3 + 1
3. 2 + 2
4. 2 + 1 + 1
5. 1 + 1 + 1 + 1
Phân tích bài toán:
Ta có thể thấy ngay cấu hình đầu tiên là: N và cấu hình cuối cùng là 1 1 1 … 1
(N chữ số 1).
Cần xây dựng thuật toán để từ cấu hình ta tìm được cấu hình tiếp theo. Từ cấu
hình a1, a2, …, ak ta có thể xây dựng cấu hình tiếp theo với quy tắc sau:
- Tìm i đầu tiên sao cho ai  1 (i giảm từ k, k-1, … 1)
- Thay ai = ai -1
- Phân tích (k-i+1) thành các số như sư:
+ Gán aj :=ai với j từ i+1 đến i + [(i+ k-i+1) div ai ];

Duyệt các cấu hình tổ hợp và ứng dụng Trang 19


THPT CHUYÊN BẮC GIANG

+ Gán aj+1 := [(k-i+1) mod ai] nếu [(k-i+1) mod ai]  0


(Số phần tử được phân tích thành bây giờ là i + [(k-i+1) div ai] + [(k-i+1) mod ai]
Ví dụ: Với N=10
*Từ cấu hình 4 4 1 1 (k=4)
- Ta tìm được i = 2
- a2 := a2 - 1 (a2 = 3)
- ta có k-i+1 div a2 = 1 và k-i+1 mod a2 = 0  số phần tử tiếp theo là 1 đó
là a3 = a2 (a3 = 3)
 Cấu hình tiếp theo là: 4 3 3
*Từ cấu hình 4 3 3 (k=3)
- Ta tìm được i =3
- a3 := a3-1 (a3 = 2)
- Ta có k-i+1 div a3 = 0 và k-i+1 mod a2 = 1  số phần tử tiếp theo là 1 đó
là a4 = 1
 Cấu hình tiếp theo là: 4 3 2 1
Chương trình của bài toán là:
Program phan_tich;
Var c: array[1..1000] of integer;
k, n: integer;
count: longint;
Stop: Boolean;
Procedure init;
Var i,j:integer;
Begin
Write('Moi nhap so nguyen duong N '); Readln(N);
k := 1;
c[k] := n;
Count := 0;
Stop := False;
end;
Procedure Result;
Var i: integer;
Begin
inc(count);
Write(count,'. ');
For i := 1 to k do write(c[i]:3);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 20


THPT CHUYÊN BẮC GIANG

writeln;
End;
Procedure Next_Division;
Var i, j, r, s, d : integer;
Begin
i := k;
while (i>0) and (c[i] =1) do dec(i);
if i>0 then
begin
c[i] := c[i]-1;
d := k-i+1;
r := d div c[i];
s := d mod c[i];
k := i;
if r>0 then
begin
for j := i+1 to i+R do c[j]:=c[i];
k := k+r;
end;
if s>0 then
begin
k := k+1;
c[k] := s;
end;
end else stop := True;
End;
Procedure Division;
Var i: integer;
Begin
While not stop do
begin
result;
next_division;
end;
Write('Bam Enter de ket thuc '); Readln
End;
BEGIN
init;
division;
END.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 21


THPT CHUYÊN BẮC GIANG

Như vậy, với mỗi bài toán như trên, khi sử dụng phương pháp sinh vào giải
quyết chúng ta thường gặp khó khăn như sau: một là việc xác định cấu hình đầu tiên
và cấu hình cuối cùng, hai là việc xác định được quy tắc để từ cấu hình đang có ta tìm
ra được cấu hình tiếp theo (sinh ra cấu hình tiếp theo). Chính vì nguyên nhân đó mà
phương pháp sinh không được sử dụng rộng rãi vào giải quyết các bài toán như thuật
toán quay lui, quy hoạch động, …Phương pháp sinh chỉ được sử dụng vào giải quyết
một số bài toán liệt kê các cấu hình tổ hợp đơn giản.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 22


THPT CHUYÊN BẮC GIANG

PHẦN 3. GIẢI THUẬT QUAY LUI


1. Ý tưởng
Trước hết ta xét 2 ví dụ sau để tạm hiểu thế nào là quay lui.
Ví dụ 1: Liệt kê dãy hoán vị từ 1..n.
Xét trường hợp n=3 ta có cây liệt kê các hoán vị của n như sau:

Hình H1.
Gọi D là tập hợp các phần tử từ 1 đến n (n=3), trong tập hợp D=(1,2,3) lần lượt
lấy các giá trị X(x1, x2, x3) để được một hoán vị.
Ví dụ: HV(1,2,3); HV(2,3,1); HV(1,3,2)...
Ban đầu trong D, các giá trị 1, 2 và 3 đều sẵn sàng.
– Bước 1, D(1,2,3) ta chọn x1=1, đánh dấu đã chọn 1 trong còn D(2,3).
– Bước 2, D(2,3) chọn x2=2, đánh dấu đã chọn 2 hay D(3).
– Bước 3, D(3) chọn x3=3, đánh dấu đã chọn 3 hay D().
 Xét thấy dãy X thoả mãn là một hoán vị X=123 (chọn đủ n=3 giá trị x1, x2 và
x3), ghi nhận hoán vị này. Tiếp tục tìm kiếm cách thay thế giá trị của các xi
(i=1..3) để được hoán vị khác.
 Thông thường và để tránh trường hợp bỏ xót nghiệm ta thường bắt đầu xét lại
theo quy luật nào đó. Trong bài toán này, ta bắt đầu từ x3 tr ở về trước. Chọn giá
trị khác 3 trong D cho x3, giải phóng phóng 3. Xét thấy trong D không còn giá trị
nào thoả mãn. Vậy ta phải xem xét lại từ x2 (tại Bước 2).

Duyệt các cấu hình tổ hợp và ứng dụng Trang 23


THPT CHUYÊN BẮC GIANG

 Tất nhiên, khi trở lại bước 2. Phần tử đang xét là x2, có nghĩa là x3 chưa nhận
giá trị nào và x2 cũng không nhận lại giá trị 2 nữa vì đã nhận trước đó rồi (để
tránh trùng nghiệm và mất thời gian)... Từ hình vẽ trong ví dụ này là ta trực tiệp
nhìn thấy. Nhưng với số lượng các phần tử trong D nhiều và rất nhiều, đồng thời
với máy tính không thể suy luận và nhìn thấy theo cách này mà phải dùng kĩ
thuật đánh dấu thông qua các biến hoặc kĩ xảo lập trình để ghi nhận các giá trị đã
hoặc chưa xét.
– (Bước 2.2)Tại đây ta chọn giá trị khác cho x2 trong D, chọn x2=3 thoả mãn.
– (Bước 2.3) Chọn một giá trị cho x3 trong D, được x3=2 thoả mãn.
 Xét thấy dãy X thoả mãn là một hoán vị X=132, để tìm các hoán vị khác ta lại
bắt đầu từ x3 ngược trở lại, tìm một giá trị trong D không lặp lại và chưa được
chọn.
 Lại tìm giá trị khác cho x3, không tìm thấy giá trị nào trong D thoả mãn, quay
lại Bước 2.2 (Bước 2), tại đây cũng không tìm được giá trị nào thoả mãn cho x2.
Tiếp tục quay về bước trước đó là Bước 1 để xác định lại x1.
– (Bước 1.2) Ta chọn x1=2, trong còn D(1,3). Tiếp theo ta chọn x2=1, trong còn
D(3) và cuối cùng chọn x3=3. Thoả mãn là một hoán vị X=213. Tiếp tục tìm các hoán
vị khác, lại quay ngược trở lại cho đến khi tìm được giá trị thoả mãn cho x i nào đó.
– Cứ như vậy cho đến khi không còn quay lui được nữa. Thuật toán kết thúc và ta
tìm xong các nghiệm của bài toán.
Ví dụ 2: Cho bàn cờ vua NxN, hãy tìm tất cả các cách đặt N quân hậu lên bàn cờ
sao cho không quân nào ăn được quân nào.

H1-1
Một lời giả của bài toán khi n=4. Hình H1-1.
Ta nhận thấy rằng mỗi quân hậu sẽ được đặt trên một hàng, nên ta gọi quân hậu
đặt ở hàng 1 là hậu 1, quân hậu đặt ở hàng 2 gọi là hậu 2… quân hậu ở hàng n gọi là
quân hậu n. Vấn đề là tìm xem hậu i được đặt tại cột j nào (j=1..n) sao cho không hậu
nào ăn được hậu nào.
* Hd:
– Đặt tất cả các hậu tại đầu mỗi hàng như hình H1-2, sau đó lần lượt đặt các quân
hậu từ 1 đến n vào các cột tương ứng từ 1 đến n sao cho không hậu nào ăn được nhau.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 24


THPT CHUYÊN BẮC GIANG

– Đặt hậu 1- vào ô 11, đặt hậu 2- vào ô 23 (ô 21 và 22 bị hậu 1 ăn được), tại dòng
3 các ô đều bị hậu 1 hoặc hậu 2 không chế, vậy đi theo cách này không được. quan sát
hình ảnh sau:
Các vị trí đánh dấu
(X) bị hậu đặt trước đó
khống chế

H1-3
– Do vậy ta phải đặt lại hậu 2.
dấu “chấm đậm”
thể hiện vị trí đã
được thử đặt
trước đó

H1-4
– Đặt hậu 2 vào ô 24, hậu 3 vào ô 32, -> không có cách đặt hậu 4, đi theo hướng
này không có lời giải. Nên ta chọn lại cách đặt hậu 3, từ hình H1-4 thấy rằng không
còn cách đặt khác cho hậu 3, nên ta quay lại và thử đạt lại hậu 2 một lần nữa, từ hình
H1-4 thấy rằng không còn cách đặt hậu 2. Ta tiếp tục quay lại tìm cách đặt lại hậu 1.
Còn với cách đặt hậu 1 tại ô 11 thì sẽ không tìm thấy lời giải. Bây giờ ta đặt hậu 1
sang ô 22 và tiếp tục với các hậu khác ta có kết quả như sau:

H1-5
– Từ bàn cờ cuối trong hình H1-5 ta thấy đây là một lời giải của bài toán, ghi nhận
nghiệm này và tiếp tục tìm lời giải khác.
– Lần lượt đặt lại các vị trí của các hậu, bắt đầu từ hậu 4 quay dần trở lại.
– Xét hậu 4: còn ô 44 nhưng lại bị hậu 2 không chế, nên ta quay lại hậu 3.
– Xét hậu 3: các ô 32, 33 và 34 bị hậu 1 hoặc 2 không chế. Quay lại hậu 2.
– Xét hậu 2: hết ô có khả năng đặt hậu, quay lại hậu 1.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 25


THPT CHUYÊN BẮC GIANG

– Xét hậu 1: đặt vào ô 13; hậu 2 đặt vào ô 21; ô 31, 32 và 33 không thoả mãn nên
đặt hậu 3 vào ô 34 và cuối cùng đặt hậu 4 vào ô 42. Ta thu được nghiệm của bài toán,
quan sát hình ảnh dưới đây:

Hình H1-6.
– Bằng cách thử lại tương tự để tìm lời giải khác cho bài toán. Xét hậu 4, hậu 3 và
hậu 2 đều không tìm được ô khác. Trở lại từ hậu 1 đặt tại ô 14… (đi theo hướng này
cũng không có lời giải - người đọc tự làm tiếp).
– Kết luận: với n=4 tồn tại hai nghiệm (2,4,1,3) và (3,1,4,2)
Tóm lại, từ các ví dụ trên cho ta thấy, nghiệm của bài toán có dạng X(x1,x2…xn)
và để giải bài toán ta thường dựa vào hai điều kiện:
– Điều kiện 1(P) để xây dựng phần tử xi: ta lần lượt đưa ra các giá trị đề cử cho xi
và kiểm tra xem các giá trị này có thoả mãn hay không. Nếu được, tiếp tục với xi+1;
nếu không, có nghĩa là đi theo hướng này không tìm được nghiệm. Ta phải quay lại
và xét lại phần tử xi-1 với một giá trị đề cử khác. Hành động này gọi là quay lui.
– Điều kiện 2(Q) để kiểm tra xem các thành phần từ x1 đến xi đã là nghiệm của
bài toán hay chưa. Nếu thoả mãn thì ghi nhận nghiệm và dừng chương trình hoặc lại
lần lượt xét lại các xi, xi-1... để tìm nghiệm khác của bài toán.

2. Thuật toán quay lui


Nội dung chính của thuật toán này thường dùng để giả các bài toán liệt kê và tối
ưu tổ hợp mà nghiệm của nó là một dãy các thành phần X=(x 1…xn) được lấy ra từ
một tập hợp dữ liệu cho trước D theo một thứ tự và điều kiện cụ thể.
Để xây dựng thuật toán này ta thực hiện theo ý tưởng sau: giả sử ta đang xét
thành phần xi trong D xem có thoả mãn điều kiện P hay không, nếu thoả mãn thì ghép
vào nghiệm sau đó xét tiếp thành phần xi+1, còn nếu không tìm thấy xi nào thảo mãn
điều kiện (P hoặc Q), thì quay trở lại thành phần trước đó là x i-1, bỏ giá trị này đi và
tại đây tìm một giá trị khác thoả mãn P cho xi-1. Sau đó lại tiếp tục tìm xi, xi+1… cho
đến khi thoả mãn Q.
Viết lại ý tưởng theo như sau:
Bước 1: Xuất phát từ tập hợp D, ta tìm được các thành phần của nghiệm
X=(x1…xi) được lấy trong D thoả P.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 26


THPT CHUYÊN BẮC GIANG

Bước 2: Nếu X thoả Q dừng thuật toán, thông báo tìm được nghiệm X. Nếu
không thoả Q chuyển sang bước 3.
Bước 3: Xét tiết thành phần xi+1 để bổ sung cho X: (x1…xi+1) thoả P. Xảy ra
trường hợp sau đây:
 Tìm được xi+1, quay lại Bước 2.
 Không, tức là với mọi xi+1 thì (x1…xi+1) không thoả P, có nghĩa là nghiệm X
theo hướng (x1…xi) đã xét sẽ không đi đến kết quả, do vậy ta phải chọn một giá
trị khác trong D cho xi để làm được điều này ta giảm i một đơn vị rồi quay về
Bước 3.
Cách làm như trên gọi là quay lui một bước để tìm nghiệm của bài toán theo
hướng khác. (thuật toán, giả thuật, tìm kiếm + quay lui hoặc backtracking).
Để đảm bảo cho việc vét cạn mọi khả năng có thể có, các giá trị đề cử không
được bỏ sót. Để đảm bảo việc xét không bị trùng lặp, khi quay lui để xác định lại các
xi cần không thử lại các giá trị đã thử rồi. Lúc này ta cần kết hợp kỹ thuật đánh dấu
hợp lý các giá trị đã thử trước đó và khi quay lui ta cần trả về trạng thái cũ.
Từ ý tưởng trên ta đưa ra hai sơ đồ giải bài toán quay lui tìm nghiệm không đệ
quy như sau:
Khởi tạo X, X thoả P Khởi tạo X, X thoả P
Repeat Repeat
If X thoả Q then If X thoả Q then
Begin Begin
Ghi nhận nghiệm; Ghi nhận nghiệm;
Exit; Exit;
[Lùi; tìm các nghiệm;] [Lùi; tìm các nghiệm;]
End; End;
If Tìm một nước đi Then Tiến If Tìm một nước đi Then Tiến
Else Lùi; Else Lùi;
Until False; Until False;
If không nghiệm Then If không nghiệm Then
Else Begin Begin
Ghi nhận vô nghiệm; Ghi nhận vô nghiệm;
Exit; Exit;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 27


THPT CHUYÊN BẮC GIANG

End; End;
– Dưới đây là cách thể hiện dùng đệ quy tìm thành phần thứ i của nghiệm:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 28


THPT CHUYÊN BẮC GIANG

Procedure Try(i : Integer);


{Xác định thành phần xi bằng đệ quy}
Var j: Integer;
Begin
For <j  tập các khả năng đề cử> do
If <chấp nhận j> then
Begin
<xác định xi theo j>;
if i = n then
Begin
<ghi nhận nghiệm>;
[exit; tìm nghiệm đầu tiên và thoát]
End
Else Begin
[ghi nhận trạng thái mới];
Try(i+1);
[trả lại trạng thái cũ];
End;
End;
End;
Trong chương trình chính chỉ cần lời gọi Try(1) để khởi động cơ cấu đệ quy hoạt
động. Tất nhiên, trước đấy cần khởi tạo các giá trị ban đầu cho các biến. Thông
thường việc này được thực hiện qua một thủ tục nào đấy mà ta gọi là Init.
Trong thủ tục Try(i: integer) ta xem xét kỹ các vấn đề sau:
– Tập các khả năng đề cử: Các giá trị đề cử thông thường lớn hơn số được chấp
nhận. Sự chênh lệch này càng lớn thì thời gian phải thử càng nhiều, vì thế càng thu
hẹp được diện đề cử càng nhiều càng tốt (nhưng không được bỏ sót !). Việc này phụ
thuộc vào việc phân tích các điều kiện ràng buộc của cấu hình để phát hiện những
điều kiện cần của cấu hình đang xây dựng. Lý tưởng nhất là các giá trị đề cử được
mặc nhiên chấp nhận. Trong trường hợp này mệnh đề <chấp nhận j> được bỏ qua (vì
thế cũng không cần các biến trạng thái).
Ví dụ: duyệt các chỉnh hợp lặp chập k của n giá trị 1,2,…,n. Mỗi chỉnh hợp được
tổ chức như một mảng k thành phần:
x[1], x[2], … ,x[k]

Duyệt các cấu hình tổ hợp và ứng dụng Trang 29


THPT CHUYÊN BẮC GIANG

trong đó, mỗi x[i] có thể lấy một trong các giá trị từ 1 đến n. Theo định nghĩa
chỉnh hợp lặp, các giá trị này là độc lập với nhau, vì thế việc đề cử bất kỳ giá trị nào
từ 1 đến n cho x[i] đều mặc nhiên được chấp nhận. Các chỉnh hợp chập 3 (k=3) của 5
(n=5) giá trị 1,2,3,4,5 gồm nk = 53 =125 bộ nghiệm.
– Điều kiện chấp nhận : Điều kiện chấp nhận một giá trị đề cử được tính toán
trong thân vòng lặp của thủ tục đệ quy Try, vì thế tiết kiệm được một phép toán trong
biểu thức này là tiết kiệm được vô số các phép toán thực sự phải làm. Thông thường,
điều kiện chấp nhận tính tại bước i phụ thuộc vào cả những bước trước, vì thế để tiết
kiệm số phép toán, người ta thường dùng một số kỹ thuật sau:
 Tổ chức những biến trạng thái để lưu trữ những thông tin cần thiết. Thay vì
phải tính lại, ta có thể truy xuất các giá trị của những biến này. Việc dùng một số
biến trạng thái, tuy phải trả giá bằng một số vùng nhớ nhất định nhưng tiết kiệm
được nhiều thời gian tính. Việc tổ chức hợp lý các biến trạng thái cũng là một kỹ
thuật làm tăng hiệu quả của việc duyệt.
 Trong những tình huống phải tính lại, cố gắng kế thừa kết quả của những bước
trước bằng cách tổ chức thêm những tham số cho thủ tục đệ quy Try để truyền
cho những bước kế tiếp.
 Nói chung, việc đưa ra được một biểu thức đơn giản để tính điều kiện chấp
nhận được là kết quả của việc phân tích kỹ lưỡng bài toán cũng như tổ chức tốt
dữ liệu. Mặt khác, điều kiện này được tính càng sát càng tốt, nó giúp ta lùi sớm
hơn (tiết kiệm thời gian hơn) trong quá trình tìm kiếm.
– Ghi nhận trạng thái mới và trả lại trạng thái cũ: tuỳ theo từng bài cụ thể.

3. Các ví dụ
(Các chương trình trong phần này được viết trên môi trường Free Pascal)

a. Chỉnh hợp lặp


Phát biểu: Một chỉnh hợp lặp chập k của n phần tử là một bộ có thứ tự gồm k
thành phần lấy từ n phần tử đã cho, các thành phần có thể được lặp lại. (n>1, k>0)
Vd: k=2, n=3. => các chỉnh hợp lặp chập 2 của 3 phần tử như sau: (1,1), (1,2),
(1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3)
Nhắc lại: duyệt các chỉnh hợp lặp chập k của n giá trị 1,2,…,n. Mỗi chỉnh hợp
được tổ chức như một mảng k thành phần:
x[1], x[2], … ,x[k]
trong đó, mỗi x[i] có thể lấy một trong các giá trị từ 1 đến n. Theo định nghĩa
chỉnh hợp lặp, các giá trị này là độc lập với nhau, vì thế việc đề cử bất kỳ giá trị nào
từ 1 đến n cho x[i] đều mặc nhiên được chấp nhận. Do vậy, trong bài toán này ta

Duyệt các cấu hình tổ hợp và ứng dụng Trang 30


THPT CHUYÊN BẮC GIANG

không cần quan tâm tới giá trị nào đã được chọn hay chưa. Ví dụ, các chỉnh hợp chập
3 (k=3) của 5 (n=5) giá trị 1,2,3,4,5 gồm nk = 53 =125 bộ nghiệm.
Cài đặt chương trình:
– Input: tệp Chlap.inp chứa hai số nguyên dương n và k.
– Output: tệp Chlap.out nhiều dòng, mỗi dòng chứa 1 số nguyên (là số tt chỉnh hợp
lặp) và 1 cấu hình chỉnh hợp lặp.
Chlap.inp Chlap.out
1: 1 1
32 2: 1 2
3: 1 3
4: 2 1
5: 2 2
6: 2 3
7: 3 1
8: 3 2
9: 3 3

{CHINH HOP LAP CHAP K CUA N}


uses crt;
const MaxN=100; { thử 100 phần tử}
fi='chlap.inp';{chua so N va k}
fo='chlap.out';{moi dong chua mot chinh hop lap}
Var
x:array[1..MaxN] of Integer;
n,k,d:integer;
f:text;
procedure Init;
var i:integer;
Begin
assign(f,fi);reset(f);
read(f,n,k);
close(f);
assign(f,fo);rewrite(f);
End;
Procedure Inkq;
var i:integer;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 31


THPT CHUYÊN BẮC GIANG

Begin
d:=d+1;write(f,d:4,': ');
for i:=1 to k do write(f,' ',x[i]); writeln(f);
End;
procedure Try(i:integer);
Var j:integer;
Begin
for j:=1 to n do
if b[j] then
begin
x[i]:=j;
if i=k then Inkq
else try(i+1);
end;
End;
BEGIN
Init;
try(1);
close(f);
END.

b. Chỉnh hợp không lặp


Phát biểu: Một chỉnh hợp không lặp chập k của n phần tử là một bộ có thứ tự
gồm k thành phần khác nhau lấy từ n phần tử đã cho (n>1, k>0, n>k).
Vd: n=3, k=2. Các chỉnh hợp không lặp chập 2 của 3 phần tử trên: (1,2), (1,3),
(2,1), (2,3), (3,1), (3,2)
Vd: n=4, k=3: cây liệt kê như sau:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 32


THPT CHUYÊN BẮC GIANG

Ta nhận thấy rằng, mỗi chỉnh hợp không lặp cũng có dạng X(x1, x2…xk). Các giá
trị đề cử của xi (i=1..k) là từ 1..n. Tuy nhiên các thành phần là đôi một khác nhau (xi
<> xj: i<>j, i,j=1..k). Do vậy ta phải sử dụng một biến mảng B để quản lý các giá trị
từ 1 đến n. nếu b[j] = true, chưa xét đến và ngược lại.
Cài đặt chương trình:
Input: tệp Chklap.inp chứa hai số nguyên dương n và k.
Output: tệp Chklap.out nhiều dòng, mỗi dòng chứa 1 số nguyên (là số tt chỉnh
hợp lặp) và 1 cấu hình chỉnh hợp lặp.
Chklap.inp Chklap.out
1: 1 2
32 2: 1 3
3: 2 1
4: 2 3
5: 3 1
6: 3 2
{CHINH HOP KHONG LAP CHAP K CUA N}
uses crt;
const MaxN=100;
fi='chklap.inp';{chua so N va K}
fo='chklap.out';{moi dong chua mot cau hinh}
var
x:array[1..MaxN] of Integer;
b:array[1..MaxN] of boolean;
n,k,d:integer;
f:text;
procedure Init;
var i:integer;
Begin
assign(f,fi);reset(f);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 33


THPT CHUYÊN BẮC GIANG

read(f,n,k);
close(f);
for i:=1 to n do b[i]:=true;
assign(f,fo);rewrite(f);
End;
Procedure Inkq;
var i:integer;
Begin
d:=d+1;write(f,d:4,': ');
for i:=1 to k do write(f,' ',x[i]); writeln(f);
End;
procedure Try(i:integer);
Var j:integer;
Begin
for j:=1 to n do
if b[j] then
begin
x[i]:=j;
b[j]:=false;
if i=k then Inkq
else try(i+1);
b[j]:=true;
end;
End;
BEGIN
Init;
Try(1);
close(f);
END.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 34


THPT CHUYÊN BẮC GIANG

Để liệt kê toàn bộ chỉnh hợp không lặp chập k, k=1..N. của các tập con
từ 1..N thì trong chương trình chính ta viết:
BEGIN
Init;
for k:=1 to n do Try(1);
close(f);
END.

c. Hoán vị
Phát biểu: Liệt kê các hoán vị của dãy số nguyên từ 1..N
Vd: Xem mục 1 phần Giải thuật quay lui.
Dùng mảng X để biểu diễn các hoán vị dạng x1x2…xn, trong đó với mỗi xi có thể
nhận một trong các giá trị từ 1..N. Vì mỗi giá trị j=1..n chỉ xuất hiện một lần trong dãy
X, nên ta dùng một mảng B để đánh dấu các giá trị, bj=true nếu j chưa được dùng. Áp
dụng thuật toán đệ quy quay lui để tìm thành phần xi như sau:
Procedure Try(i:integer);
Var j:integer;
Begin
for j:=1 to n do {các khả năng mà xi có thể nhận}
if b[j] then {nếu j chưa được dùng (thoả P)}
begin
x[i]:=j;
if i=n then PrintResult {thoả Q}
else begin
b[j]:=false; {đánh dấu đã dùng}
Try(i+1);
b[j]:=true; {trả lại trạng thái cũ - giải phóng}
end
end;
End;
Yêu cầu về dữ liệu:
Dữ liệu vào: tệp văn bản Hoanvi.inp chứa số nguyên N

Duyệt các cấu hình tổ hợp và ứng dụng Trang 35


THPT CHUYÊN BẮC GIANG

Kết quả: ghi vào tệp Hoanvi.out mỗi dòng chứa một hoán vị
Chương trình được viết như sau:
Const
MaxN=100;
fi='hoanvi.inp';{chua so N}
fo='hoanvi.out';{moi dong chua mot hoan vi}
Var
x:array[1..MaxN] of integer;
b:array[1..MaxN] of boolean;
n:integer;
f:text;
procedure Init;
var i:integer;
Begin
assign(f,fi);reset(f);
read(f,n);
for i:=1 to n do b[i]:=true;
close(f);
assign(f,fo);rewrite(f);
End;
Procedure PrintResult;
var i:integer;
Begin
for i:=1 to n do write(f,' ',x[i]); writeln(f);
End;
procedure Try(i:integer);
Var j:integer;
Begin
for j:=1 to n do
if b[j] then
begin
x[i]:=j;
if i=n then PrintResult
else begin
b[j]:=false;
try(i+1);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 36


THPT CHUYÊN BẮC GIANG

b[j]:=true;
end
end;
End;
BEGIN
Init;
Try(1);
Close(f);
END.

d. Tổ hợp
Phát biểu: Một tổ hợp chập k của n phần tử là một bộ không kể thứ tự gồm k
thành phần khác nhau lấy từ n phần tử đã cho, hai thành phần bất kì trong bộ đó phải
khác nhau. (n>1, k>0, n>k). Nói cách khác, một tổ hợp chập k của n phần tử là một
tập con k phần tử của nó.
Ví dụ 7: chập 3 của 5 phần tử

Sử dụng mảng X(x1, x2…xk) chứa các phần tử của một tổ hợp chập k của N.
Vấn đề là ta phải xác định xem giá trị của xi (i=1..n)là gì và có phải dùng kỹ thuật
đánh dấu các giá trị đã được lựa chọn hay không.
– Quan sát từ hình vẽ: Xét một nút bất kỳ có giá trị A thì các nút tiếp theo thuộc
nhánh trái nhất sẽ là A+1, nút phải nhất tối đa là N. Xét thêm một vài nhánh để xem
có xác định mộ giá trị tốt hơn N không? Từ hình vẽ ta bổ sung thêm phần tử x 0=0 là
giá trị cho nút khởi đầu.
x0=0
i=1,xi=các đề cử mới(1, 2, 3), x0+1≤xi≤n-k+i, chọn x1=1
i=2,xi=các đề cử mới(2, 3, 4), x1+1≤xi≤n-k+i, chọn x2=2
i=3,xi=các đề cử mới(3, 4, 5), x2+1≤xi≤n-k+i,
chọn x3=3; i=k => một tổ hợp 1, 2, 3
chọn x3=4; i=k => một tổ hợp 1, 2, 4

Duyệt các cấu hình tổ hợp và ứng dụng Trang 37


THPT CHUYÊN BẮC GIANG

chọn x3=5; i=k => một tổ hợp 1, 2, 5


hết giá trị thoả mãn cho x3, quay lui xét lại x2 và đi theo hướng mới.
i=2,xi=các đề cử còn(3,4), x1+1≤xi≤n-k+i, chọn x2=3
i=3,xi=các đề cử mới(4,5), x2+1≤xi≤n-k+i,
chọn x3=4; i=k => một tổ hợp 1, 3, 4
chọn x3=5; i=k => một tổ hợp 1, 4, 5
hết giá trị thoả mãn cho x3, quay lui xét lại x2 và đi theo hướng mới.
i=2,xi=các đề cử còn(4), x1+1≤xi≤n-k+i, chọn x2=4
i=3,xi=các đề cử mới(5), x2+1≤xi≤n-k+i,
chọn x3=5; i=k => một tổ hợp 1, 4, 5
hết giá trị thoả mãn cho x3, quay lui xét lại x2; x2 hết lựa chọn, lui tiếp về x1 và đi
theo hướng mới. (người đọc tự nghiên cứu tiếp)
Cài đặt chương trình:
(liệt kê mọi cấu hình tổ hợp chập k của n phần tử)
Mỗi một tổ hợp ta lưu vào một mảng X: 1≤x1≤…≤xk≤n. Suy ra giá trị đề cử cho
xi là j=1..n hoặc xét kỹ hơn sẽ là j=xi-1+1..n-k+i (tự suy nghĩ).
– Dữ liệu vào file tohopK_N.inp: chứa số nguyên N
– Kết quả file tohopK_N.out mỗi dòng chứa một tổ hợp chập k của N
Chương trình liệt kê các tổ hợp chập k của N phần tử như sau:
Const MaxN=100;
fi='tohopK_N.inp';{chua so N}
fo='tohopK_N.out';
var
x:=array[0..MaxN] of longint;
n,k,d:integer;
f:text;
Procedure Init;
Var i:integer;
Begin
assign(f,fi);reset(f);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 38


THPT CHUYÊN BẮC GIANG

read(f,n);
close(f);
assign(f,fo);rewrite(f);
x[0]:=0;
End;
Procedure PrintResult;
var i:integer;
Begin
d:=d+1;
write(f,d:4,': ');
for i:=1 to k do write(f,' ',x[i]);
writeln(f);
End;
procedure Try(i:integer);
Var j:integer;
Begin
for j:=x[i-1]+1 to n-k+i do {}
begin
x[i]:=j;
if i<k then try(i+1) else PrintResult;
end;
End;
BEGIN
Init;
for k:=1 to n do Try(1);
close(f);
END.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 39


THPT CHUYÊN BẮC GIANG

(Chú ý: Bạn đọc hãy tìm hiểu kỹ các bài toán trên trong phần cài đặt chương
trình tại các vị trí đã được đánh dấu nghiên, đậm và cũng có thể chưa đánh dấu. Vì
nếu lướt qua ta sẽ thấy các bài này na ná giống nhau, nhưng thực chất là khác nhau) .

e. Bài toán dãy nhị phân.


Liệt kê các dãy nhị phân độ dài n
Minh hoạ bài toán trường hợp n=3 dưới dạng cây nhị phân sau:

Liệt kê các dãy có chiều dài n dưới dạng x1,x2...xn, trong đó xi={0,1}. Ta có thể
sử dụng sơ đồ tìm tất cả các lời giải của bài toán. Hàm Try(i) xác định xi, trong đó xi
chỉ có 1 trong 2 giá trị là 0 hay 1. Các giá trị này mặc nhiên, được chấp nhận mà
không cần phải thoả mãn điều kiện gì. Nên Hàm try(i) có thể viết như sau :
Procedure Try ( i);
Var I,j:integer;
Begin
for j = 0 to 1 do
begin
x[i]=j;
if (i < n ) then Try (i+1);
else PrintX;
end;
end;
Thủ tục PrintX: mỗi dãy nhị phân viết trên một dòng đặt trong tệp văn bản.
Procedure PrintX;
Var i:integer;
Begin

Duyệt các cấu hình tổ hợp và ứng dụng Trang 40


THPT CHUYÊN BẮC GIANG

For i:=1 to n do write(f, x[i]);


Writeln(f);
End;
Trong lời gọi của chương trình chính: Try(1);

f. Bài toán N quân hậu.


Hướng dẫn: xem lại ví dụ 2 phần 1
Cho bàn cờ vua NxN, hãy tìm tất cả các cách đặt N quân hậu lên bàn cờ sao cho
không quân nào ăn được quân nào.
Mỗi dòng được đặt đúng một hậu đồng thời mỗi hậu cũng chỉ thuộc về một cột
nên ta quy định mảng một chiều H chứa vị trí các quân hậu trên bàn cờ, trong đó h[i]
là hậu thứ i đặt ở hàng i cột h[i] trên bàn cờ.
Mỗi quân hậu i có thể được đặt trên cột j=1..n, có nghĩa là h[i]=j sao cho ô (i,j)
chưa bị hậu nào khống chế. Để kiểm soát điều này theo luật cờ Hậu ăn ngang, dọc và
theo hai đường chéo.
Mỗi hậu được đặt trên một hàng i, nên không cần kiểm tra hàng. Ta sẽ dùng
mảng c để kiểm soát các cột trên bàn cờ, c[j]=true có nghĩa trên cột j chưa đặt hậu
nào. Các ô nằm trên cùng một đường chéo song song với đường chéo phụ, đều có
i+j=C1 (hằng số) với 2<=C1<=2n. Các ô cùng nằm trên đường chéo song song với
đường héo chính lại có i-j=C2 với 1–n<=C1<=n-1. do vậy để kiểm soát 2 đường chéo
ta dùng 2 biến c1[i+j]=true, c2[i-j]=true nếu ô (i,j) chưa bị hậu nào không chế theo
đường chéo.

Tóm lại nếu c[i]=c1[i+j]=c2[i-j]=true thì có thể đặt hậu i vào cột j.
Dữ liệu: Hau.inp chứa kích thức bàn cờ số nguyên n
Kết quả: Hau.out các vị trí hậu trên từng bàn cờ.
{Chương trình xếp n hậu}

Duyệt các cấu hình tổ hợp và ứng dụng Trang 41


THPT CHUYÊN BẮC GIANG

const MaxN=10;
fi='hau.inp';{chua so N}
fo='hau.out';
var
h:array[1..MaxN] of integer;
c:array[1..MaxN] of boolean;
c1:array[2..2*MaxN] of boolean;
c2:array[1-MaxN..MaxN+1] of boolean;
n:integer;
f:text;
procedure Init;
var i,j:integer;
Begin
assign(f,fi);reset(f);
read(f,n);
for i:=1 to n do c[i]:=true;
for i:=2 to 2*n do c1[i]:=true;
for i:=1-n to n+1 do c2[i]:=true;
close(f);
assign(f,fo);rewrite(f);
End;
Procedure PrintResult;
var i,j:integer;
Begin
writeln(f,'==========');
for i:=1 to n do begin
for j:=1 to n do if h[i]=j then write(f,'H') else write(f,'O');
writeln(f);
end;
writeln(f);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 42


THPT CHUYÊN BẮC GIANG

End;
procedure Try(i:integer);
Var j,k:integer;
Begin
for j:=1 to n do
if c[j] and c1[i+j] and c2[i-j] then
begin
h[i]:=j;
if i=n then PrintResult
else begin
c[j]:=false;c1[i+j]:=false;c2[i-j]:=false;
Try(i+1);
c[j]:=true;c1[i+j]:=true;c2[i-j]:=true;
end;
end;
End;
BEGIN
Init;
Try(1);
close(f);
END.
với n=4, kết quả tệp hau.out như sau:
==========
OHOO
OOOH
HOOO
OOHO
==========
OOHO
HOOO

Duyệt các cấu hình tổ hợp và ứng dụng Trang 43


THPT CHUYÊN BẮC GIANG

OOOH
OHOO

g. Bài toán Ngựa đi tuần


Phát biểu bài toán
Cho bàn cờ có n x n ô . Một con ngựa được phép đi theo luật cờ vua, đầu
tiên được đặt ở ô có tọa độ x0 , y0 . Hãy chỉ ra các hành trình (nếu có) của ngựa
– Đó là ngựa đi qua tất cả các ô của bàn cờ, mỗi ô đi qua đúng một lần .
Thiết kế thuật toán
Cách giải quyết rõ ràng là xét xem có thể thực hiện một nước đi kế nữa hay
không. Sơ đồ đầu tiên có thể phát thảo như sau :
Procedure Try(i);
Begin
for ( j = 1 … k)
If ( xi chấp nhận được khả năng k)
begin
Xác định xi theo khả năng k;
Ghi nhận trạng thái mới;
if( i < n2 ) Try(i+1)
else Ghi nhận nghiệm;
rả lại trạng thái cũ cho bài toán;
end;
End;
Để mô tả chi tiết thuật toán, ta phải qui định cách mô tả dữ liệu và các thao tác,
đó là :
Biểu diễn bàn cờ .
Các khả năng chọ lựa cho xi ?
Cách thức xác định xi theo j.
Cách thức gi nhận trạng thái mới, trả về trạng thái cũ.
Ghi nhận nghiệm.
. . .

Duyệt các cấu hình tổ hợp và ứng dụng Trang 44


THPT CHUYÊN BẮC GIANG

Ta sẽ biểu diễn bàn cờ bằng 1 ma trận vuông cấp n : int Ma[n][n];


Sở dĩ thể hiện mỗi ô cờ bằng 1 số nguyên thay cho giá trị boole (để đánh
dấu ô đã được đi qua chưa) là vì ta muốn lần dò theo quá trình di chuyển của con
ngựa.
Ta qui ước như sau :
Ma[x,y] = 0, Ô <x,y> ngựa chưa đi qua;
Ma[x,y] = i, Ô <x,y> ngựa đã đi qua ở bước thứ i (1 ≤ i ≤ n2 ).
Các khả năng chọn lựa cho xi ? Đó chính là các nước đi của ngựa mà xi có thể
chấp nhận được. Với cặp tọa độ bắt đầu <x,y> như trong hình vẽ, có tất cả 8 ô
<u,v> mà con ngựa có thể đi đến. Giả sử chúng được đánh số từ 1 đến 8 như hình
sau :

( 8 bước đi có thể có của con ngựa )


Một phương pháp đơn giản để có được u, v từ x, y là ta dùng 2 mảng a và b lưu
trữ các sai biệt về tọa độ .Nếu ta dùng một chỉ số k để đánh số “bước đi kế ” thì chi
tiết đó được thể hiện bởi : u = x +a[k]; v = y + b[k]; k=0..7 .
Điều kiện “chấp nhận được” có thể được biểu diễn như kết hợp của các điều kiện
:
Ô mới phải thuộc bàn cờ (1≤u ≤n và 1 ≤v≤n) và chưa đi qua ô đó, nghĩa là
Ma[u,v] = 0;
Để ghi nhận nước đi hợp lệ ở bước i, ta gán Ma[u][v] = i; và để hủy một nước đi
thì ta gán Ma[u][v] = 0.
Ma trận h ghi nhận kết quả nghiệm. Nếu có <x,y> sao cho Ma<x,y> = 0 thì đó
không phải là lời giải của bài toán , còn ngược là Ma chứa đường đi của ngựa.
Vậy thuật toán có thể mô tả như sau :
Input n, //Kích thước bàn cờ x, y;//Toạ độ xuất phát ở bước i
Output Ma;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 45


THPT CHUYÊN BẮC GIANG

Procedure Try(i, x, y:integer);


Var u,v,k:integer;
Begin
For k = 1 to 8 do
Begin
u = x + a[k];
v = y + b[k];
if (1 <= u )and(v <= n)and(Ma[u][v] == 0) then
begin
Ma[u][v] = i;
if (i <= n*n) then Try(i+1,u,v)
else PrintH();
end;
Ma[u][v] = 0;
End;
End;
Thủ tục này xuất tất cả các lời giải, nếu có.
Thủ tục đệ qui được khởi động bằng một lệnh gọi các tọa độ đầu [x0][y0] là tham
số. Ô xuất phát có trị 1, còn các ô khác được đánh dấu còn trống.
Ma[x0][y0] = 1; Try(2,x0, y0);
Các mảng a và b có thể khởi đầu như sau :
int a[8]= {2,1,-1,-2,-2,-1,1,2};
int b[8]= {1,2,2,1,-1,-2,-2,-1};
Các lời giải sau là một số kết quả cho từ thuật toán trên :
n=5 x=1 y=1
1 6 15 10 21
14 9 20 5 16
19 2 7 22 11
8 13 24 17 4
25 18 3 12 23
Với n = 5, các tọa độ xuất phát sau không có lời giải : (2,3), (3,2)...
Cài đặt chương trình

Duyệt các cấu hình tổ hợp và ứng dụng Trang 46


THPT CHUYÊN BẮC GIANG

{Duong di cua QuanMa tren ban co vua, moi o di qua 1 lan}


Uses crt;
Const MaxN=10;
fi='quanma.inp';{n/x y}
fo='quanma.out';
a:array[1..8] of integer=(2,1,-1,-2,-2,-1,1,2);
b:array[1..8] of integer=(1,2,2,1,-1,-2,-2,-1);
Var
n,d,x,y,u,v:integer;
ma:array[1..MaxN,1..MaxN] of integer;{thu tu quan ma}
f:text;
Procedure Init;
Var i,j:integer;
Begin
assign(f,fi);reset(f);
readln(f,n); read(f,x);read(f,y);
for i:=1 to n do for j:=1 to n do ma[i,j]:=0;
ma[x,y]:=1;
close(f);
assign(f,fo);rewrite(f);d:=0;
End;
Procedure PrintResult;
Var i,j:integer;
Begin
d:=d+1;
writeln(f,'=====',d,'=====');
for i:=1 to n do begin
for j:=1 to n do write(f,ma[i,j]:2,'.');
writeln(f);
end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 47


THPT CHUYÊN BẮC GIANG

writeln(f);
End;
Procedure Try(i:integer;x,y:integer);
Var j,k,u,v:integer;
Begin
for j:=1 to 8 do
begin
u:=x+a[j];
v:=y+b[j];
if (ma[u,v]=0)and(u>=1)and(u<=n)and(v>=1)and(v<=n) then
begin
ma[u,v]:=i;
if i=n*n then PrintResult
else Try(i+1,u,v);
ma[u,v]:=0;
end;
end;
End;
BEGIN
Init;
Try(2,x,y);
Close(f);
END.

h. Mê cung (later)

 Quay lui là ban đầu ta tiến, tiến và tiến cho đến khi không tiến được nữa thì
lui và lui cho đến khi có đường đi mới, ta lại tiến và tiến… lại lui, lui cho đến khi hết
đường lui. Hết việc!

Duyệt các cấu hình tổ hợp và ứng dụng Trang 48


THPT CHUYÊN BẮC GIANG

4. Tài liệu tham khảo.

a. Thầy nguyễn Thanh Tùng tóm tắt về TÌM KIẾM QUAY LUI.
Tìm kiếm quay lui (Backtraking) là phương pháp tìm kiếm lời giải trên cây
phương án. Phương pháp này được sử dụng chủ yếu để tìm một lời giải thỏa mãn một
số yêu cầu nào đó theo nguyên tắc mở rộng dần dần lời giải.
Các bài toán điển hình:
Mã đi tuần: Tìm đường đi của quân mã trên trên bàn cờ kích thước NN, sao cho
mỗi ô trên bàn cờ (trừ ô xuất phát) được đi qua đúng một lần và trở về ô xuất phát,
Đặt quân hậu: Đặt ttối đa số quân hậu trên bàn cờ NN, sao cho không có hai
quân hậu nào ở vị trí ăn nhau,
Bài toán người bán hàng rong: Tìm đường đi khép kín ngắn nhất qua mỗi đỉnh
của đồ thị đúng một lần,
Xâu không lặp: Với M ký tự khác nhau hãy tìm xâu có độ dài N, sao cho mọi
xâu con L ký tự liên tiếp đều khác nhau,
Xâu phản đối xứng: Với M ký tự khác nhau hãy tìm xâu có độ dài N, sao cho
nếu lấy xâu con bất kỳ các ký tự liên tiếp nhau và chia nó thành hai xâu con liên tiếp
nhau, thì hai xâu con mới này khác nhau với mọi cách chia,
Thoát khỏi mê cung: Điều khiển rô bốt tìm đường ra khỏi mê cung.
Nguyên tắc cơ bản của phương pháp tìm kiếm quay lui là như sau:
Chia tập tìm kiếm thành nhiều tập con,
Đánh số các tập con theo một tiêu chuẩn nào đó  có các tập P1, P2, . . ., Pk,

P
P1 P3
P2
P11 P14
P12
Với mỗi tập con nhận được: xác định một trong số các khả năng:
Không cần xét tiếp tập này,
Bài toán trở nên quá đơn giản và tìm được một lời giải,

Duyệt các cấu hình tổ hợp và ứng dụng Trang 49


THPT CHUYÊN BẮC GIANG

Qay lại bước a) với tập con này.


Tiêu chuẩn phân chia tập con: thỏa mãn một trong số các tính chất:
Nhận được bài toán giống như ban đầu, nhưng có kích thước bé hơn,
Nhận được bài toán đơn giản hơn,
Nhận được bài toán với một số tính chất mới không có trong bài toán ban đầu.
Tiêu chuẩn đánh số các tập con:
Theo thứ tự từ điển của một cấu trúc dữ liệu,
Theo khả năng, triển vọng tồn tại nghiệm.
Tìm kiếm quay lui về bản chất gần giống các giải thuật đệ quy, nhưng có một số
khác biệt cơ bản:
Người lập trình điều khiển được quá trình duyệt theo các hướng có triển vọng,
Không cần lưu toàn bộ các nút rẽ nhánh trong tìm kiếm,
Có thể dễ dàng ngắt và quay lui khi cần thiết.
Chính vì những đặc điểm trên nên giải thuật này thường áp dụng để giải các bài
toán theo phương pháp nhánh và cận.
Các mô đun cơ bản:
Khởi tạo tìm kiếm quay lui: init,
Mở rộng lời giải : Extend,
Chuyển sang tập mới: Change,
Kiểm tra tính hợp lệ của lời giải : Check.
Sơ đồ chung :
init ;
repeat
Extend ;
Check ;
While not ok do
begin
change;
check
end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 50


THPT CHUYÊN BẮC GIANG

until kt;

b. Các tác giả khác


– Nguyễn Đức Nghĩa, Nguyễn Tô Thành. Toán rời rạc, NXB ĐHQGHN, 2003
– ThS.Trần Đức Huyên. Phương pháp giải các bài toán trong Tin học. NXBGD.
2004.
– Nguyễn Xuân Huy. Sáng tạo trong thuật toán và lập trìng. NXBGD. 2007.
– Lê Minh Hoàng. Giải thuật và lập trình – A.D.A DSAP Textbook, DHSPHN,
1999-2002. <Internet>
– Trần Tuấn Minh. Thiết kế và đánh giá thuật toán. Đà lạt. <Internet>
– Lê Minh Hoàng. Bài giảng các chuyên đề.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 51


THPT CHUYÊN BẮC GIANG

PHẦN IV. ỨNG DỤNG


I. KHÁI NIỆM BÀI TOÁN TỐI ƯU.
1. Một số khái niệm
* Phát biểu bài toán: Có nhiều bài toán mà việc giải nó đưa về việc duyệt các
cấu hình tổ hợp thoả mãn các điều kiện nào đó. Với mỗi cấu hình tổ hợp, ta sẽ tính
toán theo một cách nào đó (tuỳ theo yêu cầu của bài toán) để được một giá trị bằng số.
Giá trị đó thể hiện giá trị sử dụng của cấu hình (gọi là giá của cấu hình hay giá của
phương án).
* Bài toán đặt ra: “Trong số các cấu hình tổ hợp chấp nhận được, hãy lựa chọn
một cấu hình có giá trị sử dụng tốt nhất (lớn nhất hoặc nhỏ nhất”
Các bài toán như vậy gọi là bài toán tối ưu tổ hợp.
a. Phương án và giá của phương án
Mỗi cấu hình tổ hợp gọi là một phương án của bài toán (hay còn gọi là một lời
giải của bài toán). Với mỗi phương án của bài toán ta tính toán được một con số gọi là
giá của phương án.
b. Hàm mục tiêu của bài toán
Nếu ta gọi tập các phương án của bài toán là D.
Khi đó, với mỗi phương án x thuộc D cho chúng ta một giá trị số duy nhất tương
ứng với nó. Do đó xác định một hàm số:
f:DR
x  y=f(x)
Hàm f(x) như vậy gọi là hàm mục tiêu của bài toán
Vậy: Bài toán tối ưu tổ hợp là bài toán: “Tìm Max{f(x)| xD}” hoặc “Tìm
Min{f(x)| |xD}”, với D là tập các phương án của bài toán.
c. Giá trị tối ưu và phương án tối ưu
Một phương án x*D mà tại đó f(x*) đạt giá trị min hoặc max gọi là phương án
tối ưu của bài toán.
Giá trị f(x*) gọi là giá trị tối ưu của bài toán. Như vậy:
Với bài toán tìm max thì: f(x*) lớn hơn hoặc bằng f(x) với mọi x thuộc D;
Với bài toán tìm min thì: f(x*) nhỏ hơn hoặc bằng f(x) với mọi x thuộc D;
Chú ý:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 52


THPT CHUYÊN BẮC GIANG

 Giá trị tối ưu của bài toán là duy nhất.


 Phương án tối ưu của bài toán có thể có nhiều
d. Các ví dụ
Ví dụ 1: Bài toán cái túi
Một nhà thám hiểm cần đem theo một cái túi có trọng lượng không quá b. Có n
đồ vật cần đem theo. Đồ vật thứ j có trọng lượng là a j và giá trị sử dụng là cj (j = 1, 2,
3, ..,n). Hỏi rằng nhà thám hiểm cần đem theo các đồ vật nào để cho tổng giá trị sử
dụng của các đồ vật đem theo là lớn nhất?
Dữ liệu: Vào từ file văn bản CAITUI.INP:
 Dòng đầu ghi 2 số nguyên dương n và b (n < 100).
 Dòng thứ hai ghi các số nguyên không âm a1, a2, .. ,an.
 Dòng thứ ba ghi các số nguyên không âm c1, c2, .. ,cn.
Kết quả: Ghi ra file CAITUI.OUT:
 Dòng đầu ghi tổng giá trị các đồ vật đem theo ứng với phương án tìm được.
 Ghi chỉ số của các đồ vật đem theo
Ví dụ:
CAITUI.INP CAITUI.OUT
4 8 15
5 3 2 4 1 2
10 5 3 6
Phân tích:
– Mỗi đồ vật chỉ có 2 khả năng lựa chọn (2 trạng thái) là: được chọn vào túi để
mang đi hoặc không được chọn vào túi để mang đi.
Do đó, mỗi phương án chọn đồ vật để mang theo của nhà thám hiểm là một bộ
x=(x1,x2,…,xn), trong đó xi = 0 hoặc 1, i=1,2,…,n; Với ý nghĩa xi = 0 tương đương
với việc đồ vật i không được chọn vào túi, còn xi = 1 tương đương với việc đồ vật i
được chọn vào túi.
Như vậy, mỗi phương án lựa chọn các đồ vật là một chỉnh hợp lặp chập n của 2
phần tử {0,1} (hay một dãy nhị phân độ dài n).
Điều kiện chấp nhận của phương án x là “tổng khối lượng các đồ vật được chọn
n
nhỏ hơn hoặc bằng b”, tức là: g(x) = a
i 1
i * xi < b

Duyệt các cấu hình tổ hợp và ứng dụng Trang 53


THPT CHUYÊN BẮC GIANG

n
Giá của phương án x bằng: f(x) = c
i 1
i * xi

Kết luận:
Bài toán cái túi là một bài toán tối ưu tổ hợp: “Tìm Max{f(x)| xD}, với
D={x|x=(x1,x2,…,xn), xi = 0 hoặc 1, i=1,2,…,n; và g(x) < b}
Ví dụ 2: Bài toán thuê thợ
Có n công việc được đánh số từ 1 đến n và có n thợ được đánh số từ 1 đến n.
Mỗi công việc i biết chi phí cần trả để thợ j hoàn thành công việc này là c[i,j],
với i,j = 1,2,3,..,n.
Yêu cầu: Hãy tìm phương án thuê thợ với tổng chi phí phải trả là nhỏ nhất sao
cho các công việc đều hoàn thành, biết rằng mỗi thợ chỉ thực hiện một công việc và
mỗi việc chỉ do một thợ thực hiện.
Dữ liệu: Vào từ file văn bản THUETHO.INP có dạng
 Dòng đầu ghi số n. (N <= 100)
 n dòng tiếp theo, mỗi dòng i ghi n số c[i,j], j = 1,2…,n tương ứng là chi phí
cần trả để thợ j hoàn thành công việc i (i = 1,2,…,n).
Kết quả: Ghi ra file văn bản THUETHO.OUT gồm:
 Dòng đầu ghi tổng chi phí thuê thợ.
 Dòng thứ 2 ghi n số, trong đó số thứ i (i=1,2,..n) là số hiệu của thợ thực hiện
công việc i.
Ví dụ:
THUETHO.INP THUETHO.OUT
5 32
4 8 17 19 7 1 2 5 4 3
12 6 17 19 10
8 19 19 7 7
17 9 17 3 7
7 16 12 16 8
*Phân tích:
– Mỗi phương án thuê thợ là một hoán vị của n phần tử {1,2, ...,n}. Kí hiệu
x={x1,x2, ...,xn} trong đó xi = j nghĩa là việc i thuê thợ j; i=1,2,..,n; j  {1,2, ...,n}.
– Tập các phương án: D = {x| x = {x1,x2, ...,xn}, xi  {1,2, ...,n}, i=1,2,..,n và
xi<>xj nếu i<>j }
n
– Giá của phương án: f(x) =  C[i, xi ]
i

Duyệt các cấu hình tổ hợp và ứng dụng Trang 54


THPT CHUYÊN BẮC GIANG

Bài toán đưa về bài toán tối ưu tổ hợp: “Tìm Min{f(x)| x  D}”

2. Một số phương pháp giải bài toán tối ưu tổ hợp


* Phương pháp duyệt
Dùng kiến thức toán học đã biết, dùng suy luận, đánh giá
đưa ra được phương án tối ưu.
* Phương pháp đánh giá nhánh cận
* Cặp ghép
....

Duyệt các cấu hình tổ hợp và ứng dụng Trang 55


THPT CHUYÊN BẮC GIANG

II. PHƯƠNG PHÁP DUYỆT GIẢI BÀI TOÁN TỐI ƯU


1. Tư tưởng chủ đạo
Lần lượt duyệt các cấu hình của bài toán. Đối với mỗi cấu hình thoả mãn điều
kiện của bài toán (mỗi phương án của bài toán) ta đi tính giá của phương án đó. So
sánh giá của tất cả các phương án với nhau để tìm ra phương án tối ưu và giá trị tối
ưu.
Trong quá trình duyệt ta luôn giữ lại phương án tốt hơn. Phương án tốt nhất cho
đến thời điểm đang duyệt gọi là phương án mẫu. Giá trị của phương án mẫu gọi là kỷ
lục tạm thời.
Khi duyệt xong tất cả các phương án thì sẽ tìm được phương án tối ưu và giá trị
tối ưu. Tuy nhiên, trên thực tế với những bài toán có kích thước lớn (số phương án
nhiều) thì thời gian duyệt lâu dẫn đến không khả thi. Do đó, trong quá trình duyệt ta
nên hạn chế bớt phép duyệt (không duyệt các phương án mà ta đã biết chắc chắn rằng
phương án đó không thể là phương án tối ưu của bài toán).
Có hai cách duyệt:
 Duyệt toàn bộ (vét cạn)
 Duyệt hạn chế (phương pháp duyệt có đánh giá nhánh cận)

2. Cấu trúc của phương pháp duyệt tổng quát


*Phát biểu bài toán tối ưu tổ hợp bằng cách khác:
Tìm MAX{f(x), x thuộc D} hoặc Tìm MIN{f(x), x thuộc D}
trong đó:
+) D = {x| x=(x1,x2, ..., xn)  A1 × A2 ×... ×An ; x thoả mãn tính chất P}
+) A1 , A2 ,... ,An là các tập hữu hạn phần tử.
+) Ai là tập gồm các khả năng đề cử cho thành phần xi
* Phương pháp duyệt viết dưới dạng mô hình quay lui có cấu trúc tổng quát
như sau:
Procedure Khởitạo;
begin
Đọc dữ liệu vào
Khởi tạo các giá trị ban đầu cho các biến
end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 56


THPT CHUYÊN BẮC GIANG

{}
Procedure Cập Nhật Kỷ Lục;
begin
- <Tính giá phương án nếu chưa tính>
- Nếu giá p/án > kỷ lục (hoặcp/án > kỷ lục) thì
begin
kỷ lục := giá p/án;
giữ lại p/án;
end;
end;
Procedure Try(k : integer);
begin
for ak  Ak do
if <chấp nhận ak> then
begin
xk := ak;
<Tính giá của phương án bộ phận cấp k;>
<Xác định trạng thái mới của bài toán nếu cần>
if k = n then Cập Nhật Kỷ Lục
else try(k+1);
<Hoàn nguyên trạng thái của bài toán nếu cần>
end;
end;
Procedure Inkq;
begin
<in kỷ lục và phương án tối ưu>
end;
BEGIN
Khởitạo;
Try(1);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 57


THPT CHUYÊN BẮC GIANG

inkq;
END.

III. BÀI TẬP ÁP DỤNG


Bài 1: Cân thăng bằng
Có một cái cân đĩa (cân thăng bằng) và n quả cân trọng lượng khác nhau (các
quả cân được đánh số từ 1 đến n). Quả cân số hiệu i có trọng lượng a i. Người ta muốn
cân một vật có trọng lượng p. Hãy tìm cách đặt vật và các quả cân lên đĩa để cân
thăng bằng sao cho số quả cân phải dùng là ít nhất.
Dữ liệu:Vào từ file CAN.INP gồm 3 dòng:
 Dòng đầu ghi số n.
 Dòng thứ 2 ghi các số a1, a2, … ,an.
 Dòng cuối cùng ghi giá trị p. Các số ai và p là nguyên dương. Giới hạn n < 30,
a1 + a2 + …+an < 32767
Kết quả: Ghi ra file CAN.OUT
Nếu không có phương án đặt thì ghi số -1 tại dòng đầu tiên, trái lại kết quả ghi
trên 2 dòng.
 Dòng đầu gồm: số quả cân đặt cùng trên một đĩa với vật, tiếp theo là số hiệu
của các quả cân này.
 Dòng thứ 2 gồm: số quả cân đặt trên đĩa còn lại, tiếp theo là số hiệu của các
quả cân này.
Trong các tệp dữ liệu các số trên cùng một dòng ghi cách nhau bởi dấu cách.
Ví dụ:
CAN.INP CAN.OUT
10 2 2 3
27 10 73 95 60 55 87 77 75 2 4 5
131
*Phân tích thuật toán:
Mỗi quả cân có 3 khả năng lựa chọn (hay còn gọi là có 3 trạng thái) được kí hiệu
là 0,1,2, đó là: không đặt vào đĩa nào (0), đặt ở đĩa có vật (1), đặt ở đĩa không có vật
(2);
 Mỗi phương án (mỗi cấu hình) của bài toán là bộ: x[1], x[2], …, x[n] trong
đó x[i] là khả năng lựa chọn của quả cân i: x[i] = 0,1,2 (i=1..n).

Duyệt các cấu hình tổ hợp và ứng dụng Trang 58


THPT CHUYÊN BẮC GIANG

Bài toán đưa về duyệt các chỉnh hợp lặp chập n của 3 phần tử {0,1,2}, tính giá
của từng phương án và cập nhật kỷ lục để giữ lại phương án tốt nhất.
Để tăng hiệu quả trong việc duyệt trước hết ta sắp xếp các quả cân giảm dần theo
trọng lượng và thứ tự đề cử cho mỗi thành phần x[i] là 0, 1, 2.
Cách 1: Không dùng thêm tham số trong thủ tục Try
{ chay cham ,n < 50}
Program CanThangBang;
uses crt;
const
fi ='can.inp';
fo ='can.out';
maxn=300;
var a,a1 :array[1..maxn] of integer;
kqx1,kqx2,x1,x2 :array[1..maxn] of integer;
tongtua :array[1..maxn] of longint;
{tongtua[i] := a[i+1] + a[i+2] + … + a[n]}
n, p :integer;
le, ri :longint;
{tổng khối lượng các quả cân được đặt vào đĩa chứa vật và đĩa không chứa vật
của phương án bộ phận, ban đầu le := p; ri :=0}
min,t,d,d1,d2,kqd1,kqd2 :integer;
f:text;
cs :array[1..maxn] of integer;
Procedure init;
var i:integer;
Begin
assign(f,fi); reset(f);
readln(f,n);
for i:=1 to n do read(f,a[i]);
a1:=a;
readln(f,p);
close(f);
le := p;
ri := 0;
min := maxint;
d1 := 0;
d2 := 0;
tongtua[n]:=a[n];
for i:=n-1 downto 1 do tongtua[i]:=tongtua[i+1]+a[i];
end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 59


THPT CHUYÊN BẮC GIANG

{------------------------------*****---------------------------}
procedure Sort;
var i,j,tg: integer;
begin
for i:=1 to n do cs[i]:=i;
for i:=1 to n-1 do
for j:=i+1 to n do
if a[j]>a[i] then
begin
tg:=a[i];a[i]:=a[j];a[j]:=tg;
tg:=cs[i];cs[i]:=cs[j];cs[j]:=tg;
end;
tongtua[n]:=a[n];
for i:=n-1 downto 1 do tongtua[i]:=tongtua[i+1]+a[i];
end;
Procedure cnkl;
Begin
if d < min then
Begin
min := d;
kqd1 := d1;
kqd2 := d2;
kqx1 := x1;
kqx2 := x2;
End;
End;
Procedure try(i:integer);
var j:integer;
Begin
for j:=0 to 2 do
Begin
if j=1 then
Begin
inc(d1);
x1[d1] := i;
le :=le + a[i];
End;
if j=2 then
Begin
inc(d2);
x2[d2] := i;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 60


THPT CHUYÊN BẮC GIANG

ri := ri + a[i];
End;
d:=d1+d2;
if i=n then Begin if le=ri then cnkl; End
else if (d < min) and (abs(le - ri) <= tongtua[i + 1]) then try(i + 1);
if j=1 then
Begin
dec(d1);
le := le - a[i];
End;
if j=2 then
Begin
dec(d2);
ri := ri - a[i];
End;
d := d1 + d2;
end;
End;
Procedure result;
var i:integer;
Begin
assign(f,fo); rewrite(f);
write(f,kqd1,' ');
for i:=1 to kqd1 do write(f,cs[kqx1[i]],' ');
writeln(f);
write(f,kqd2,' ');
for i:=1 to kqd2 do write(f,cs[kqx2[i]],' ');
close(f);
End;
BEGIN
init;
sort;
try(1);
result;
END.
Cách 2: Dùng thêm tham số trong thủ tục Try
Mỗi quả cân có 3 khả năng lựa chọn (hay còn gọi là có 3 trạng thái) được kí hiệu
là 1,0,-1, đó là: đặt ở đĩa có vật (1), không đặt vào đĩa nào (0), đặt ở đĩa không có vật
(-1);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 61


THPT CHUYÊN BẮC GIANG

 Mỗi phương án (mỗi cấu hình) của bài toán là bộ: x[1], x[2], …, x[n] trong
đó x[i] là khả năng lựa chọn của quả cân i: x[i] = -1,0,1 (i=1..n).
Trong thủ tục Try: S là khối lượng chênh lệch giữa hai đĩa cân ở bước i-1 truyền
lại cho bước thứ i, sau đó được tính lại khi đã chọn xong ở bước i và truyền lại cho
bước i+1
program CanThangBang;
uses crt;
const fin='Can.inp';
fout='Can.out';
maxn=70;
var a,cs : array[1..maxn] of integer;
x,kqx : array[1..maxn] of integer;
ts : array[1..maxn] of longint;{tổng sau ts[i]:=a[i+1]+a[i+2]+…+a[n]}
n,d,t : integer;
min,kqi : integer;
f : text;
p,s:longint;
{s là chênh lệch khối lượng giữ hai đĩa cân, được khởi tạo ban đầu là p}
{d là số quả cân được chọn đặt lên đĩa}
procedure Init;
var i: integer;
begin
assign(f,fin);reset(f);
readln(f,n);
for i:=1 to n do read(f,a[i]);
readln(f);
readln(f,p);
close(f);
min:=maxint;
s:=p;
d:=0;
t:=0;
end;
procedure Sort;
var i,j,tg: integer;
begin
for i:=1 to n do cs[i]:=i;
for i:=1 to n-1 do
for j:=i+1 to n do
if a[j]>a[i] then

Duyệt các cấu hình tổ hợp và ứng dụng Trang 62


THPT CHUYÊN BẮC GIANG

begin
tg:=a[i];a[i]:=a[j];a[j]:=tg;
tg:=cs[i];cs[i]:=cs[j];cs[j]:=tg;
end;
ts[n]:=0;
for i:=n-1 downto 1 do ts[i]:=a[i+1]+ts[i+1];
end;
Procedure Try(i,s,d: integer);
{d là số quả cân đã dùng đến bước i-1 truyền lại cho bước i}
var j: integer;
begin
for j:=1 downto -1 do
if d+abs(j)<min then {có thể đánh giá ngay tại đây: nếu thêm 1 quả cân nữa
đặt vào đĩa mà không tốt hơn kỷ lục của phương án mẫu thì không xây dựng tiếp pa}
begin
t:=s-j*a[i];
if abs(t)<=ts[i] then {độ lệch phải < tổng các quả cân chưa chọn}
begin
x[i]:=j;
if t=0 then
if d+abs(j)<min then
begin
min:=d+abs(j);
kqi:=i;
kqx:=x;
exit;
end;
if i<n then Try(i+1,t,d+abs(j));
end;
end;
end;
procedure Result;
var c1,c2,i: integer;
begin
assign(f,fout);rewrite(f);
if min=maxint then writeln(f,-1)
else
begin
c1:=0;c2:=0;
for i:=1 to kqi do
begin

Duyệt các cấu hình tổ hợp và ứng dụng Trang 63


THPT CHUYÊN BẮC GIANG

if kqx[i]=-1 then inc(c1);


if kqx[i]=1 then inc(c2);
end;
write(f,c1,' ');
for i:=1 to kqi do if kqx[i]=-1 then write(f,cs[i],' ');
writeln(f);
write(f,c2,' ');
for i:=1 to n do if kqx[i]=1 then write(f,cs[i],' ');
end;
close(f);
end;
BEGIN
Init;
Sort;
Try(1,p,0);
Result;
END.
Bài 2 : Lập lịch ưu tiên đúng hạn.
Có n công việc được đánh số từ 1 đến n và có một máy để thực hiện chúng. Biết:
+ pi là thời gian cần thiết để hoàn thành công việc i.
+ di là thời hạn hoàn thành công việc i.
Mỗi công việc cần được thực hiện liên tục từ lúc bắt đầu cho tới khi kết thúc,
không cho phép ngắt quãng. Khoảng thời gian thực hiện hai công việc bất kì chỉ được
có nhiều nhất 1 điểm chung. Thời điểm bắt đầu thực hiện n công việc tính từ 0. Giả sử
ci là thời điểm hoàn thành công việc i. Khi đó, nếu c i > di ta nói công việc i bị hoàn
thành trễ hạn, còn nếu nếu ci < di ta nói công việc i bị hoàn thành đúng hạn.
Yêu cầu: Tìm trình tự thực hiện các công việc sao cho số công việc được hoàn
thành đúng hạn là lớn nhất.
Dữ liệu: Vào từ file văn bản LIC* HDH.INP:
+ Dòng đầu tiên chứa số nguyên dương n (0 < n < 100).
+ Dòng thứ 2 chứa n số nguyên dương p1, p2, … , pn.
+ Dòng thứ 3 chứa n số nguyên dương d1, d2, … , dn.
Kết quả: Ghi ra file LIC* HDH.OUT gồm:
+ Dòng đầu tiên ghi số lượng công việc được hoàn thành đúng hạn theo
trình tự tìm được.
+ Dòng tiếp theo ghi trình tự thực hiện các công việc đã cho.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 64


THPT CHUYÊN BẮC GIANG

Ví dụ:
LIC* HDH.INP LIC* HDH.OUT
6 4
4 1 2 3 1 1 3 4 6 2 5
5 6 6 7 8
*Phân tích thuật toán:
- Một trình tự thực hiện các công việc (một phương án của bài toán) là một hoán
vị của n phần tử {1, 2, …, n}.
Cụ thể: mỗi phương án là 1 bộ x = (x1, x2, …,xn); trong đó xi  {1, 2, …, n}, xi
<> xj nếu i<>j;
- Giá của phương án x (số công việc đúng hạn) bằng: f(x) = k
i
Với điều kiện g(x) =  p < di với mọi i = 1,2, …, k
i
i =1
Bài toán lập lịch đúng hạn đưa về bài toán: “Tìm Max{f(x)| xD},
với D={x|x=(x1,x2,…,xn), xi  {1, 2, …, n}, xi <> xj nếu i<>j; và g(x) < di}
Văn bản chương trình:
program LapLichUuTienDungHan;
uses crt;
const fin = 'LIC* HD.INP';
fout = 'LIC* HD.OUT';
maxn = 100;
var p,d,x,kqx : array[1..maxn] of integer;
cx,kqcx : array[1..maxn] of boolean;
f : text;
n : integer;
tg,count,max: integer;
{----------------------------------------------------------}
procedure Init;
var i: integer;
begin
assign(f,fin);reset(f); readln(f,n);
for i:=1 to n do read(f,p[i]);
readln(f);
for i:=1 to n do read(f,d[i]);
close(f);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 65


THPT CHUYÊN BẮC GIANG

fillchar(cx,sizeof(cx),true);
tg := 0; count:=0; max:=0;
end;
{----------------------------------------------------------}
procedure Try(i: integer);
var j: integer;
begin
for j:=1 to n do
begin
if cx[j] then
begin
x[i]:=j;
cx[j]:=false;
tg := tg + p[j];
if (tg <= d[j]) then inc(count);
if (i = n) then
begin
if count>max then
begin
max:=count;
kqx:=x;
end;
end
else if count+n-i>max then Try(i+1);
if tg <= d[j] then dec(count);
tg := tg - p[j];
cx[j]:=true;
end;
end;
end;
{---------------------------------------------------------}
procedure Result;
var i: integer;
j: integer;
begin
assign(f,fout);rewrite(f);
writeln(f,max);
for i:=1 to n do write(f,kqx[i],' ');
close(f);
end;
{----------------------------------------------------------}

Duyệt các cấu hình tổ hợp và ứng dụng Trang 66


THPT CHUYÊN BẮC GIANG

BEGIN
Init;
Try(1);
Result;
END.
Bài 4 : Truyền tin
Người ta cần truyền n gói tin được đánh số từ 1 đến n từ một điểm phát đến một
điểm thu. Để thực hiện việc truyền tin có thể sử dụng m đường truyền được đánh số
từ 1 đến m. Biết rằng nếu truyền j gói tin theo đường truyền tin i thì chi phí phải trả là
sij (sij là số nguyên dương, sij < 32767, i =1,2,..,m, j = 1,2,…,n).
Yêu cầu: Hãy xác định số lượng gói tin cần truyền theo mỗi đường truyền tin để
việc truyền n gói tin được thực hiện với tổng chi phí phải trả là nhỏ nhất.
Dữ liệu: Vào từ file văn bản TTIN1.INP:
+ Dòng đầu tiên chứa hai số nguyên dương n và m (n,m < 100) .
+ Dòng thứ i trong số m dòng tiếp theo chứa n số nguyên dương s i1, si2, .., sin ,
i=1,2,…,m.
Kết quả: Đưa ra file văn bản TTIN1.OUT:
+ Dòng đầu tiên chứa S là tổng chi phí phải trả theo cách truyền tin tìm được.
+ Dòng thứ hai chứa m số nguyên không âm q1, q2, .. ,qm, trong đó qi là số gói tin
cần truyền theo đường truyền tin i.
Ví dụ:
TTIN1.INP TTIN1.OUT
3 3 4
20 20 20 0 2 1
4 3 10
1 3 20

Bài 5 : Thuê máy


Một trung tâm có n máy tính (cấu hình giống nhau) dùng để cho thuê trong tháng
(từ ngày 1 đến ngày 31), thời gian thuê tính theo đơn vị ngày. Đầu tháng, trung tâm
nhận được yêu cầu của m khách hàng (đánh số từ 1 đến m), mỗi khách hàng cần thuê
một máy trong một số ngày nào đấy thuộc tháng. Giả thiết rằng, đối với mỗi khách
hàng, hoặc trung tâm từ chối, hoặc trung tâm đồng ý cho thuê theo đúng như yêu cầu
của khách. Với mỗi ngày, gọi tần số sử dụng máy là số máy túnh được sử dụng trong

Duyệt các cấu hình tổ hợp và ứng dụng Trang 67


THPT CHUYÊN BẮC GIANG

ngày đó. Hãy lập một phương án cho thuê máy để tổng tần số sử dụng máy trong
tháng là lớn nhất.
Dữ liệu: Vào từ file văn bản THUEMAY.INP gồm:
+ Dòng đầu ghi các giá trị n, m.
+ m dòng tiếp theo, theo thứ tự 1, 2,…,m, mỗi dòng ghi yêu cầu của một khách:
bắt đầu là số ngày mà khách cần thuê, tiếp theo là các ngày trong tháng mà khách cần
thuê. Các giá trị trên cùng một dòng ghi cách nhau ít nhất một dấu trắng.
Kết quả: Đưa ra file văn bản THUEMAY.OUT:
+ Dòng đầu ghi số khách được thuê.
+ Dòng tiếp theo ghi các số hiệu khách được thuê, các số hiệu này phân cách
nhau ít nhất một dấu trắng.
+ Dòng cuối ghi tổng tần số sử dụng máy.
Hạn chế kích thước: số máy, số khách không vướt quá 30
Ví dụ:
THUEMAY.INP THUEMAY.OUT
3 10 6
5 1 3 4 6 7 1 2 6 8 9 10
1 1 20
2 3 6
3 2 4 5
6 1 2 3 4 5 6
2 2 3
5 1 3 4 6 7
5 2 4 5 6 7
4 1 2 4 5
3 3 5 6
Bài 6 : Dãy số
Cho dãy số gồm n số nguyên dương a1, a2, …, an (n < 1000) và số nguyên dương
k (k < 50).
Yêu cầu: Tìm dãy con nhiều phần tử nhất của dãy đã cho và có tổng các phần tử
chia hết cho k.
Dữ liệu: Vào từ file văn bản DAYSO.INP gồm:
+ Dòng đầu tiên chứa hai số n, k được ghi cách nhau bởi ít nhất một dấu trắng.
+ Các dòng tiếp theo chứa các số a1, a2, … ,an được ghi cách nhau ít nhất một
dấu trắng hoặc dấu xuống dòng.
Kết quả: Ghi ra file văn bản DAYSO.OUT

Duyệt các cấu hình tổ hợp và ứng dụng Trang 68


THPT CHUYÊN BẮC GIANG

+ Dòng đầu tiên ghi m là số phần tử của dãy con tìm được.
+ Các dòng tiếp theo ghi dãy m chỉ số các phần tử của dãy đã cho có mặt trong
dãy con tìm được. Các chỉ số được ghi cách nhau ít nhất một dấu trắng hoặc xuống
dòng.
Ví dụ:
DAYCON.INP DAYCON.OUT
10 3 9
2 3 5 7 1 3 2 4 5
9 6 12 7 6 7 10 8
11 15

* Phân tích thuật toán: Chia từng số hạng của dãy cho k để tìm số dư, tính tổng
các số dư. Sau đó tính r := tổngdư mod k;
+ Nếu r = 0 thì kết luận lấy được cả dãy
+ Ngược lại: nếu tìm trong dãy có 1 số chia cho k dư r thì chỉ cần loại số đó và
dãy cần tìm gồm n-1 số còn lại;
Nếu không rơi vào 2 trường hợp trên thì thì ta đi “tìm cách loại đi ít nhất các
phần tử để tổng các số còn lại chia hết cho k”:
 Trước hết ta đi tìm số lượng từng loại số dư: SLDU[i] = j nghĩa là các số
chia cho k dư i có j số (i=0,1,2, …,k-1)
 Mỗi cách loại các phần tử được xác định bởi 1 bộ: x[1], x[2], …, x[n], trong
đó x[i]=j, nghĩa là các số chia cho k dư i cần loại đi j số sao cho tổng các số còn
lại chia hết cho k.
 Rõ ràng khi đi xây dựng các x[i] thì giá trị đề cử ở bước i sẽ là các số
nguyên từ 0..SLDU[i].
Bài toán đưa về: Duyệt các cách loại phần tử (các bộ x[1], x[2], …, x[n], x[i] =
0..SLDU[i]), sau đó cập nhật kỷ lục để tìm ra 1 cách loại ít phần tử nhất. Kết quả của
bài toán sẽ gồm các phần tử không bị loại, khi đó sẽ gồm nhiều phần tử nhất.
Như vậy, từ 1 bài toán tìm Max ta đã chuyển về 1 bài toán tìm Min có độ
phức tạp nhỏ hơn (thời gian thực hiện nhanh hơn), đưa về việc giải 1 bài toán có kích
thước nhỏ hơn, đơn giản hơn;
{Chương trình này có thể chạy nhanh với n=10000, k= 1000}
program Dayso;
uses crt;
const
fi = 'DAYCON.INP';

Duyệt các cấu hình tổ hợp và ứng dụng Trang 69


THPT CHUYÊN BẮC GIANG

fo = 'DAYCON.OUT';
maxn = 10000;
maxk = 1000;
type
ksldu = array [0..maxk-1] of integer;
kad = array [1..maxn ] of integer;
kloai = array[1..maxn] of boolean;
kx = array [1..maxk-1] of integer;
var
a : kad;
du : kad;{du[i] = j nghia la phan tu thu i chia cho k duoc so du la j}
sldu : ksldu;{sldu[i] = j so luong cac so chia cho k du i la bang j}
loai : kloai;
{danh dau cac chi so can loai bo}
x,kqx : kx;
n, k, d : integer;
min, tongdu, r,tdloai, slloai : longint;
f : Text;
procedure nhap;
var
inp: text;
i, t: integer;
begin
assign(f, fi); reset(f);
readln(f, n, k);
for i:=1 to n do read(f,a[i]);
close(f);
tongdu := 0;
for i:=1 to n do begin du[i] := a[i] mod k; tongdu:= tongdu+du[i]; end;
r := tongdu mod k;
assign(f,fo); rewrite(f);
end;
procedure XetDacBiet;
var
i, j: integer;
begin
if r=0 then
begin
writeln(f,n);
for i:=1 to n do
begin write(f,i:6); if (i mod 100) = 0 then writeln(f); end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 70


THPT CHUYÊN BẮC GIANG

close(f);
halt;
end;
for i:=1 to n do loai[i] := false;
j :=0;
for i:=1 to n do if du[i] = r then
begin
loai[i] := true; j := i; break;
end;
if j>0 then
begin
writeln(f,n-1);
for i:=1 to n do
if not loai[i] then
begin write(f,i,' '); if (i mod 100) = 0then writeln(f); end;
close(f);
halt;
end;
end;
procedure try(i: integer);
var j : integer;
begin
for j:=0 to sldu[i] do
begin
x[i] := j; {nghĩa là: trong các số chia cho k dư i cần loại đi j số}
slloai := slloai + j; {số lượng số cần loại đi}
tdloai := tdloai + i*j; {tổng dư của các số loại đi}
if i = k-1 then
begin
if (tdloai mod k = r) and (slloai < min) then
begin
min := slloai;
kqx := x;
end;
end
else if slloai < min then try(i+1);
tdloai := tdloai - i*j;
slloai := slloai - j;
end;
end;
Procedure Tim;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 71


THPT CHUYÊN BẮC GIANG

var i: integer;
Begin
for i:=1 to k-1 do sldu[i] :=0;
for i:=1 to n do sldu[du[i]] := sldu[du[i]] + 1;
slloai := 0; tdloai := 0;
min := maxlongint;
try(1);
for i:=1 to n do loai[i] := false;
for i:=1 to n do
if kqx[du[i]] <>0 then
begin
dec(kqx[du[i]]);
loai[i] := true;
end;
writeln(f,n-min);
for i:=1 to n do
if not loai[i] then
begin
write(f,i,' ');
if i mod 100 =0 then writeln(f);
end;
close(f);
End;
begin
nhap;
XetDacBiet;
Tim;
end.
Bài 7: Chia kẹo
Có N gói kẹo (N nguyên dương, N < 50), các gói kẹo được đánh số từ 1 đến N,
gói kẹo thứ i có Ai cái kẹo (Ai nguyên dương và Ai < 20; i = 1, 2, 3, …, N).
Hãy tìm một cách chia các gói kẹo thành hai nhóm sao cho tổng số kẹo trong hai
nhóm chênh lệch nhau ít nhất.
Dữ liệu: Nhập N và N số A1, A2, …, AN từ file văn bản KEO.INP có cấu trúc
gồm 2 dòng: dòng đầu ghi số N, dòng thứ hai ghi các số lần lượt từ A1 đến AN. Các
số bắt đầu ghi từ đầu dòng theo thứ tự từ trái sang phải.
Kết quả: Ghi ra tệp văn bản KEO.OUT gồm 3 dòng:
Dòng đầu tiên ghi 3 số X, Y, Z, trong đó X là số kẹo chênh lệch giữa hai nhóm,
Y là số kẹo của nhóm 1, Z là số kẹo của nhóm 2;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 72


THPT CHUYÊN BẮC GIANG

 Dòng thứ hai ghi số hiệu các gói kẹo của nhóm 1.
 Dòng thứ ba ghi số hiệu các gói kẹo của nhóm 2.
Ví dụ:
KEO.INP KEO.OUT
8 1 56 57
19 5 20 13 16 20 18 2 3 5 6
12478
Bài 8: Xếp hàng mua vé
Có N người xếp hàng mua vé. Ta đánh số họ từ 1 đến N theo thứ tự đứng trong
hàng (từ đầu hàng đến cuối hàng). Thời gian phục vụ bán vé cho người thứ i là t i. Mỗi
người cần mua một vé nhưng được quyền mua tối đa 2 vé, vì thế một số người có thể
nhờ người đứng ngay trước mình mua hộ. Người thứ i nhận mua hộ vé cho người thứ
i+1 thì thời gian mua vé cho 2 người là ri.
Yêu cầu: Tìm phương án sao cho N người đều có vé với thời gian ít nhất.
Dữ liệu: đọc từ file văn bản MUAVE.INP gồm có 3 dòng, dòng thứ nhất ghi số
nguyên dương N, dòng thứ hai ghi N số t1, t2,…, tN, dòng thứ ba ghi N-1số r1, r2, …,
rN-1.
Kết quả: ghi ra file văn bản MUAVE.OUT gồm: dòng thứ nhất là tổng thời gian
phục vụ bán vé. Dòng tiếp theo ghi chỉ số của các khách hàng cần rời khỏi hàng
Ví dụ:
MUAVE.INP MUAVE.O
UT
5 17
2 5 7 8 4 2 4
3 9 10 10
Bài 9: Tạo chuỗi kí tự
Cho 3 ký tự A, B, C và một số nguyên dương N ( 4 <=N<=100).
Yêu cầu: Từ 3 ký tự trên hãy viết chương trình tạo ra chuỗi ký tự thoả mãn các
tính chất sau:
 Có độ dài N.
 Không có hai chuỗi con liên tiếp nào giống nhau.
 Số ký tự B là ít nhất
Dữ liệu: Nhập số N từ file văn bản CHUOIKT.INP
Kết quả: Ghi ra file văn bản CHUOIKT.OUT có cấu trúc:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 73


THPT CHUYÊN BẮC GIANG

 Dòng đầu ghi số ký tự B ít nhất trong chuỗi


 Dòng 2 ghi chuỗi tìm được
Ví dụ:
CHUOIKT.INP CHUOIKT.OUT
10 2
ACABACBCAC
Bài 10: Các thanh gỗ
Ông Hoà Bình có một tập hợp các thanh gỗ có độ dài bằng nhau là L.
Ông chặt các thanh gỗ ra một cách ngẫu nhiên nhưng độ dài các mẩu con đều có
độ dài nguyên.
Về sau ông Hoà Bình có ý định gắn các mẩu con để khôi phục lại các thanh gỗ
ban đầu nhưng lại quên mất độ dài L. Ông đã quyết định tạo lập các thanh gỗ có độ
dài bằng nhau.
Hãy giúp ông Hoà Bình tạo lập các thanh gỗ có độ dài như nhau và cành ngắn
càng tốt.
Dữ liệu: vào cho từ file văn bản THANHGO.INP
 Dòng đầu ghi số N (N <50), số lượng các mẩu gỗ
 Trên mỗi dòng trong N dòng tiếp theo ghi Li (0 < Li < 100), là số nguyên, độ
dài mẩu gỗ thứ i.
Kết quả: ghi ra file văn bản THANHGO.OUT
 Dòng đầu ghi L là độ dài ngắn nhất tìm được
 Trên mỗi dòng ghi độ dài các mẩu gỗ dùng để ghép thành thanh gỗ đó
* Ví dụ:
THANHGO.INP THANHGO.OUT
10 9
2 234
3 531
5 72
2 63
7
4
6
1
3

Duyệt các cấu hình tổ hợp và ứng dụng Trang 74


THPT CHUYÊN BẮC GIANG

3
Bài 11: Trồng cây
Nhà Ông GĐ Sở văn hoá tỉnh BG có một đại sảnh rộng và đẹp. Ông có ý định
trồng một số loại cây cảnh vào N chậu hoa đã được thiết kế cố định thành một hàng
trên đại sảnh, các chậu hoa có số thứ tự từ 1 đến N tính từ trái sang phải. Biết được ý
thích của Ông, các bạn bè đã mua tặng ông M cây cảnh khác nhau để trồng vào các
chậu hoa nói trên. Mỗi cây cảnh có một số hiệu duy nhất trong khoảng từ 1 đến M.
Ông muốn trồng các cây cảnh vào các chậu hoa theo thứ tự ràng buộc “nếu có cây
cảnh số hiệu i và cây cảnh số hiệu j mà i<j thì cây cảnh số hiệu i sẽ được trồng bên
trái cây cảnh số hiệu j”. Tất cả các cây cảnh đều được trồng vào các chậu hoa sao cho
đảm bảo ràng buộc về thứ tự các số hiệu. Nếu số chậu hoa nhiều hơn số cây cảnh thì
những chậu hoa không dùng tới sẽ để trống. Mỗi chậu hoa chỉ được trồng một cây
cảnh.
Mỗi chậu hoa có thiết kế về hình dáng, kích thước, kiểu cách có thể khác nhau
(các cây cảnh cũng có thể khác nhau). Vì thế, khi một cây cảnh i được trồng vào một
chậu hoa j sẽ có một giá trị thẩm mỹ nhất định, giá trị này được biểu diễn bởi một số
nguyên aij. Các chậu hoa để trống có giá trị bằng 0.
Yêu cầu: Hãy tìm cách trồng các cây cảnh vào các chậu hoa tuân theo ràng buộc
về thứ tự sao cho tổng các giá trị thẩm mỹ là lớn nhất. Nếu có nhiều cách trồng có
cùng giá trị thẩm mỹ thì chỉ cần đưa ra đúng một cách.
Dữ liệu: vào từ file văn bản TREE.INP gồm:
Dòng đầu tiên ghi 2 số M và N (1 < N < 100; M < N < 100).
M dòng tiếp theo, mỗi dòng ghi N số, dòng i ghi a[i,1],.., a[i,N] với -50<a[i,j]<
50 là già trị thẩm mỹ khi trồng cây cảnh i vào chậu hoa j.
Kết quả: ghi ra file văn bản TREE.OUT:
 Dòng đầu tiên là tổng số thẩm mỹ của cách trồng.
 Dòng thứ hai ghi M số, số thứ k ghi số hiệu của chậu hoa mà cây cảnh số hiệu
k trồng vào.
Ví dụ:
TREE.INP TREE.
OUT
35 53
7 23 -5 -24 2 4
16 5
5 21 -4 10

Duyệt các cấu hình tổ hợp và ứng dụng Trang 75


THPT CHUYÊN BẮC GIANG

23
-21 5 -4 -
20 20
Bài 12 :Rôbốt quét vôi
Có 9 căn phòng (đánh số từ 1 đến 9) đã được quét vôi với mầu trắng, xanh hoặc
vàng. Có 9 rôbốt (đánh số từ 1 đến 9) phụ trách việc quét vôi các phòng. Mỗi rôbốt
chỉ quét vôi một số phòng nhất định. Việc quét vôi được thực hiện nhờ một chương
trình cài sẵn theo qui tắc:
 nếu phòng đang có màu trắng thì quét màu xanh,
 nếu phòng đang có màu xanh thì quét màu vàng,
 nếu phòng đang có màu vàng thì quét màu trắng,
Cần phải gọi lần lượt một số các rôbốt ra quét vôi (mỗi lần một rôbốt, một rôbốt
có thể gọi nhiều lần và có thể có rôbốt không được gọi. Rôbốt được gọi sẽ quét vôi tất
cả các phòng mà nó phụ trách) để cuối cùng các phòng đều có màu trắng.
Hãy tìn một phương án như vậy sao cho lượng vôi phải quét là ít nhất. Giả thiết
rằng lượng vôi cho mỗi lượt quét đối với các phòng là như nhau.
Dữ liệu: vào từ fie văn bản ROBOTQV.INP gồm các dòng: 9 dòng đầu, mỗi
dòng mô tả danh sách các phòng được quét vôi bởi một rôbốt theo thứ tự từ rôbốt 1
đến rôbốt 9. Mỗi dòng như vậy gồm các số hiệu phòng viết sát nhau. Chẳng hạn dòng
thứ 2 có nội dung : 3578
Mô tả rôbốt 2 phụ trách việc quét vôi các phòng 3, 5, 7, 8.
Dòng cuối mô tả màu vôi ban đầu của các phòng. Dòng gồm 9 kí tự viết sát
nhau, kí tự thứ i biểu diễn màu vôi của phòng i với qui ước: kí tự T chỉ màu trắng, kí
tự X chỉ màu xanh, kí tự V chỉ màu vàng, .
Kết quả: ghi ra tệp văn bản ROBOTQV.OUT gồm một dòng dưới dạng:
 Nếu không có phương án thì ghi một chữ số 0.
 Trái lại ghi dãy thứ tự các rôbốt được gọi (các số hiệu rôbốt viết sát nhau)
Ví dụ:
ROBOTQV.INP ROBOTQV.INP
159 2455688
123
357
147
5
369
456

Duyệt các cấu hình tổ hợp và ứng dụng Trang 76


THPT CHUYÊN BẮC GIANG

789
258
XVXVXVTXT
*Phân tích thuật toán
 Mỗi phương án gọi Rôbốt là một chỉnh hợp lặp chập 9 của 3 phần tử {0,1,2}.
Kí hiệu x = (x1, x2, ...,xn); với xi := j nghĩa là Rôbốt i được gọi j lần.
 Gọi r[i] là xâu kí tự cho biết danh sách các phòng do Rôbốt i phụ trách
9
Khi đó giá của phương án x =  xi * length(r[i])
i

Bài 13: Xâu đối xứng


Xâu kí tự S được gọi là đố xứng nếu các ký tự cách đều đầu và cuối là giống
nhau. Ví dụ ABA và abcba là những xâu đối xứng.
Xét các xâu có không quá 2000 kí tự, chỉ chứa các kí tự A..Z, a..z, 0..9. Hãy xoá
đi ít kí tự nhất để thu được xâu đối xứng.
Dữ liệu: vào từ file văn bản XDX.INP
 Dòng đầu tiên chứa số n biểu thị chiều dài xâu
 Từ dòng thứ hai là n kí tự viết liền nhau, có thể trải trên nhiều dòng, mỗi dòng
không quá 70 kí tự
Kết quả: Ghi ra tệp văn bản XDX.OUT chứa số m biểu thị số kí tự cần xoá
Ví dụ:
XDX.INP XDX.OUT
9 3
bbC1221bA
Bài 14: Xếp lịch 1
Cho N công việc, với mỗi công việc cho biết tiền công thu được khi thực hiện
công việc này, thời gian để hoàn thành, thời điểm cuối cùng phải kết thúc. Hãy xếp
lịch thực hiện sao cho thu được nhiều tiền công nhất.
Dữ liệu: Vào từ file văn bản XL1.INP gồm:
+ Dòng đầu là số nguyên dương N.
+ N dòng sau, dòng i+1 ghi 3 số tg, tdkt, gt tương ứng là thời gian cần thiết để
hoàn thành, thời điểm bắt buộc phải xong, giá trị tiền công của công việc i, với
(i=1,...,N);
Kết quả: Ghi ra file văn bản XL1.OUT như sau:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 77


THPT CHUYÊN BẮC GIANG

+ Dòng đầu tiên là tổng giá trị tiền công;


+ Các dòng tiếp theo, mỗi dòng ghi 4 số: i, T1, T2, gt tương ứng là số hiệu công
việc, thời điểm bắt đầu, thời điểm kết thúc, giá trị của công việc được chọn.
Ví dụ:
XL1.I XL1.OU
NP T
10 329
1 4 5 0 1
89 25
5 5 1 1 2
86 89
4 11 3 2 6
83 83
5 7 6 6 9
84 61
1 2 10 9
25 14 71
3 11
61
6 11
61
4 7
28
3
10 1
5
14 71
Bài 15: Cho thuê máy tính
Tại thời điểm 0, ông chủ cho thuê máy tính nhận được đơn đặt hàng thuê sử
dụng của N khách hàng. Các khách hàng được đánh số từ 1 đến N. Khách hàng i cần
sử dụng máy từ thời điểm di đến thời điểm ci (di và ci là các số nguyên và 0 < di < ci
< 1000000000), và sẽ trả tiền sử dụng máy là pi (pi nguyên, 0 < pi < 10000000);
Hãy xác định xem ông chủ cần nhận phục vụ những khách hàng nào sao cho
khoảng thời gian sử dụng máy tính của hai khách hàng được nhận phục vụ bất kì
không giao nhau và tổng tiền thu được từ phục vụ là lớn nhất.
Dữ liệu: vào từ file văn bản RENTING.INP. Dòng đầu tiên ghi số N (0 < N <
1000). Dòng thứ i trong N dòng tiếp theo ghi ba số di, ci, pi cách nhau bởi dấu trống,
i=1,2,..,N.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 78


THPT CHUYÊN BẮC GIANG

Kết quả: ghi ra file văn bản RENTING.OUT. Dòng đầu tiên ghi hai số nguyên
dương theo thứ tự là số lượng khách hàng nhận được phục vụ và tổng tiền thu được.
Dòng tiếp theo ghi chỉ số của khách hàng được phục vụ.
Ví dụ:
RENTING.INP RENTING.OUT RENTING.INP RENTING.OUT
3 2 180 4 2 1100
150 500 150 2 3 400 821 800 2 4
1 200 100 200 513 500
400 800 80 100 325 200
600 900 600
Bài 16: Xoay ô
Một diện tích được tạo bởi các ô vuông, gồm N hàng và N cột (các hàng được
đánh số từ 1 đến N theo chiều từ trên xuống dưới và các cột được đánh số từ 1 đến N
theo chiều từ trái sang phải). Mỗi ô vuông được chia đôi theo đường chéo: Một nửa
màu đen, một nửa màu trắng. Trạng thái của mỗi ô vuông được mã hóa từ 0 đến 3
theo hình vẽ sau:

0 1 2 3
Một diện tích được xác định bởi trạng thái các ô vuông của nó. Có thể thay đổi
trạng thái này bằng cách xoay các ô theo chiều kim đồng hồ một trong những góc 90,
180o, 270o.
Diện tích được gọi là hợp lệ nếu các phần cùng màu của các ô sát nhau không
được có chung cạnh, chẳng hạn diện tích trong hình 1 là không hợp lệ, hình 2 là hợp
lệ:

Hình 2 Hình 1
Hãy xác định xem diện tích đã cho đã hợp lệ chưa? Nếu chưa, cần tìm cách
xoay lại một số ô cần thiết để diện tích là hợp lệ, sao cho số ô cần xoay là ít nhất.
Dữ liệu vào cho trong file văn bản ROT.INF, dòng đầu là số N, tiếo theo là bảng
N dòng, N cột ghi trạng thái của các ô tương ứng. Các giá trị trên cùng một dòng ghi
cách nhau ít nhất một dấu trắng.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 79


THPT CHUYÊN BẮC GIANG

Lời giải đưa ra file văn bản ROT.INF, trong đó nếu diện tích đã cho là hợp lệ thì
chỉ cần ghi một số 0, trái lại văn bản gồm dòng đầu tiên là số ô cần xoay, các dòng
tiếp, mỗi dòng mỗi dòng mô tả một ô cần xoay bao gồm: tọa độ hàng, tọa độ cột và
góc cần xoay theo chiều kim dồng hồ của ô (tính theo đơn vị độ - là một trong các giá
trị 90, 180, 270). Các số này ghi cách nhau ít nhất một dấu trắng.
Thí dụ:
ROT.INF (Hình 1) ROT.OUT diện tích nhận được cho bởi hình 2.
4 6 Giới hạn kích thước N  10.
2 0 1 0 1 1 270
2 0 3 2 2 1 270
2 0 2 3 2 3 180
1 2 1 0 2 4 180
3 2 270
4 2 180

 Phân tích thuật toán


 Văn bản chương trình
Program Xoayo;
uses crt;
const fi = 'ROT.INP';
fo = 'ROT.OUT';
otren:array[0..3,0..3] of integer = ((0,1,1,0),(0,1,1,0),(3,2,2,3),(3,2,2,3));
oduoi:array[0..3,0..3] of integer = ((0,0,3,3),(1,1,2,2),(1,1,2,2),(0,0,3,3));
maxn=10;
var a,b,kqb:array[1..maxn,1..maxn]of integer;
f:text;
n,min,i:integer;
Procedure init;
var i,j:integer;
Begin
assign(f,fi); reset(f);
readln(f,n);
for i:=1 to n do
for j:=1 to n do read(f,a[i,j]);
b:=a;
close(F);
min:=n*n;
End;
procedure cnkl;
var i,k,j,d:integer;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 80


THPT CHUYÊN BẮC GIANG

begin
d:=0;
for i:=1 to n do
for k:=i-1 downto 1 do
begin
b[k,i]:=otren[b[k,i-1],b[k+1,i]];
b[i,k]:=oduoi[b[i-1,k],b[i,k+1]];
end;
for i:=1 to n do
for j:=1 to n do
if a[i,j]<>b[i,j] then
Begin
inc(d);
if d > min then exit;
End;
if d < min then
begin
min:=d;
kqb:=b;
end;
end;
Procedure try(i:integer);
var j:integer;
begin
for j:=0 to 3 do
begin
b[i,i]:=j;
if i=n then cnkl else
try(i+1);
end;
end;
procedure viet;
var i,j,doo:integer;
begin
assign(f,fo);rewrite(f);
writeln(f,min);
for i:=1 to n do
for j:=1 to n do
if a[i,j]<>kqb[i,j] then
begin
doo:=(kqb[i,j]-a[i,j])*90;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 81


THPT CHUYÊN BẮC GIANG

if kqb[i,j]<a[i,j] then doo:=doo+360;


writeln(f,i,' ',j,' ',doo);
end;
close(f);
end;
BEGIN
init;
try(1);
viet;
END.
Bài 17: Bìa đục lỗ
Có N phiếu đục lỗ hình vuông. Tren mỗi phiếu đục lỗ có K*K hình tròn được bố
trí thành K hàng ngang, K hàng dọc, mỗi hàng K lỗ, sao cho tất cả các hình tròn được
đục thủng thì vị trí các lỗ đục là trùng nhau khi xếp các phiếu này thành một chồng,
cho dù có một số phiếu đã được xoay 90o, 180o, 270o.
Trên mỗi phiếu có mọtt số hình tròn được đục thủng.

Khi xếp các phiếu thành một chồng, các hình tròn ở cùng một vị trí tạo thành
một cột.
Yêu cầu: Hãy chỉ ra một số ít nhất các phiếu cần xoay sao cho nếu xếp chúng thành
một chồng thì trên mỗi cột đều có ít nhất một hình tròn được đục thục, hoặc cho biết
điều này không thể thực hiện được.
Dữ liệu: Vào từ file văn bản BN4.INF:
- Dòng đầu là 2 số nguyên N, K (1N20,
2K10).
- Dòng thứ i trong N dòng tiếp theo chứa
K*K số 0, 1 cho biết trạng thái các hình tròn của
phiếu thứ i, liệt kê theo hàng ngang, từ trái sang
phải và từ trên xuống dưới, trong đó số 1 (0) chỉ
ra vị trí tương ứng là lỗ đục (không đục).
Các số trên 1 dòng cách nhau ít nhất một
dấu cách.
Kết quả: Đưa ra file văn bản BL4.OUT:

Duyệt các cấu hình tổ hợp và ứng dụng Trang 82


THPT CHUYÊN BẮC GIANG

- Dòng đầu tiên chứa số nguyên M là số phiếu cần xoay. M = -1 là không có cách
xoay.
- Trong trường hợp M  0, thì dòng thứ 2 chứa N số nguyên R1, R2,…, RN, Ri bằng 0,
1, 2 hoặc 3, cho biết bìa thứ i cần xoay Ri*90o theo chiều kim đồng hồ.
- Nếu có nhiều cách chọn M phiếu để xoay thì chỉ cần nêu một trong số đó.
Ví dụ:
BL4.INP BL4.OUT
5 3 3
1 0 0 0 1 0 0 0 0 0 0 1 1 3
0 1 0 1 0 0 0 0 0
1 0 0 0 1 0 0 0 1
0 1 0 0 0 0 1 0 0
1 0 0 1 0 0 0 0 0

Chú ý: - Các file bài làm phải được đặt tên tương ứng là BL3.PAS và BL4.PAS.

Bài 18: Bầu cử


Bài 19: Chọn K số để tổng lớn nhất
Cho ma trận kích thước m.n gồm các số nguyên nằm trong khoảng 0..99.
Yêu cầu: Hãy chọn ra k số sao cho tổng các số được chọn là lớn nhất, biết rằng
trên mỗi dòng, mỗi cột chọn nhiều nhất một số.
Dữ liệu: Vào từ file văn bản CHONK.INP có cấu trúc:
 Dòng đầu ghi 3 số m, n, k. (1< k < m,n < 100)
 M dòng tiếp theo, mỗi dòng ghi n số tương ứng với các giá trị trong ma trận
Kết quả: Ghi ra file văn bản CHONK.OUT có cấu trúc:
 Dòng đầu tiên ghi tổng lớn nhất tìm được
 K dòng tiếp theo, mỗi dòng ghi 3 số: số thứ nhất là giá trị của số tìm được, hai
số sau là toạ độ [dòng, cột] của số được chọn.
Ví dụ:
CHONK.INP CHONK.OUT
5 4 4 72
12 9 7 17 19 4 1
2 12 9 19 19 3 2
21 19 15 7 9 2 3

Duyệt các cấu hình tổ hợp và ứng dụng Trang 83


THPT CHUYÊN BẮC GIANG

19 8 5 3 25 5 4
1 2 8 25
*Phân tích thuật toán:
Mỗi phương án của bài toán là một bộ có thứ tự gồm k thành phần: x = (x1, x2,
…, xk), trong đó xi = (dòng i, cột i), dòng i = 1, 2, …, m và cột i = 1, 2, …, n; nếu i
<> j thì xi <> xj ;
Vì dòng i có m khả năng lựa chọn và cột i có n khả năng lựa chọn nên bộ hai
thành phần (xi, yi) có m*n khả năng lựa chọn.
k
Giá của mỗi phương án bằng f(x) =  a[xi]
1

“Bài toán đưa về: duyệt các chỉnh hợp không lặp chập k của m*n phần tử, tính
giá của các phương án, só sánh giá của các phương án với nhau và giữ lại phương án
có giá lớn nhất”
* Văn bản chương trình
Program chonKSoCotongLonNhat;
uses crt;
const
fi = 'CHONK.INP';
fo = 'CHONK.OUT';
Maxmn = 100;
var
a: array[1..maxmn,1..maxmn] of byte;
dong, cot, kqd, kqc : array[1..maxmn] of byte;
cxd, cxc : array[1..maxmn] of boolean;
m, n, k : byte;
tmax, s : longint;
procedure init;
var
f: text;
i,j : integer;
begin
assign(f,fi); reset(f);
readln(f,m,n,k);
for i := 1 to m do
for j:=1 to n do read(f,a[i,j]);
close(f);
fillchar(cxd, sizeof(cxd), true);

Duyệt các cấu hình tổ hợp và ứng dụng Trang 84


THPT CHUYÊN BẮC GIANG

fillchar(cxc, sizeof(cxc), true);


s := 0; tmax := -maxint;
end;
procedure cnkl;
var i,j : integer;
begin
if s > tmax then
begin
tmax := s;
kqd := dong;
kqc := cot;
end;
end;
procedure inkq;
var i,j : integer;
f : text;
begin
assign(f,fo); rewrite(f);
writeln(f,tmax);
for i := 1 to k do writeln(f,a[kqd[i],kqc[i]],' ',kqd[i],' ',kqc[i]);
close(f);
end;
procedure try(i:integer);
var d,c : integer;
begin
for d := 1 to m do
for c:=1 to n do
begin
if cxd[d] and cxc[c] then
begin
dong[i] := d;
cot[i] := c;
s := s + a[d,c];
cxd[d] := false;
cxc[c] := false;
if i = k then cnkl
else try(i+1);
cxd[d] := true;
cxc[c] := true;
s := s - a[d,c];
end;

Duyệt các cấu hình tổ hợp và ứng dụng Trang 85


THPT CHUYÊN BẮC GIANG

end;
end;
BEGIN
init;
try(1);
inkq;
END.
Bài 20: Tìm tổng nhỏ nhất
Cho ma trận gồm m dòng, n cột có các phần tử là các số nguyên a[i,j], trong đó
|a[i,j]|<30000 (i=1..m, j=1..n).
Yêu cầu: Hãy chọn trên mỗi dòng, mỗi cột của ma trận đúng một số sao cho
không có hai số nào thuộc cùng một dòng hay cùng một cột để tổng các số được chọn
là nhỏ nhất.
Dữ liệu: Vào từ file văn bản TONGMIN.INP có cấu trúc:
 Dòng đầu ghi 2 số nguyên m, n. (1 < m < 100, 1 < n < 30);
 Trong m dòng tiếp theo, dòng thứ i ghi n số a[i,j] với i=1..m, j=1..n;
Kết quả: Ghi ra file văn bản TONGMIN.OUT có cấu trúc:
 Dòng đầu tiên ghi tổng nhỏ nhất tìm được
 Trong n dòng tiếp theo, mỗi dòng ghi 3 số: số thứ nhất là giá trị của số được
chọn, hai số sau là toạ độ [dòng, cột] của số được chọn.
Ví dụ:
TONGMIN.INP TONGMIN.OUT
7 4 -67
8 6 -18 0 -18 1 3
-15 1 15 0 -15 2 1
-5 0 9 13 -14 4 2
11 -14 -12 12 -20 7 4
19 3 14 12
20 -4 2 17
10 -8 5 -20
*Phân tích thuật toán:
* Nếu m < n thì : “duyệt các chỉnh hợp không lặp chập m của n phần tử
{1,2,…,n}, tức là mỗi phương án cần tìm là một bộ x = (x1, x2, …, xm), xi = j nghĩa
là chọn số ở hàng i cột j; i = 1, 2,.., m; j = 1,2, …,n; tính giá của phương án x bằng
m
công thức f(x) =  a[i,x[i]] và giữ lại phương án có giá trị nhỏ nhất”
i=1

Duyệt các cấu hình tổ hợp và ứng dụng Trang 86


THPT CHUYÊN BẮC GIANG

* Nếu m > n thì : “duyệt các chỉnh hợp không lặp chập n của m phần tử
{1,2,…,m}, tức là mỗi phương án cần tìm là một bộ x = (x1, x2, …, xn), xi = j nghĩa
là chọn số ở cột i hàng j; i = 1, 2,.., n; j = 1,2, …,m; tính giá của phương án x bằng
n
công thức f(x) =  a[x[i],i] và giữ lại phương án có giá trị nhỏ nhất”
i=1

Duyệt các cấu hình tổ hợp và ứng dụng Trang 87


THPT CHUYÊN BẮC GIANG

KẾT LUẬN

Hiện nay chưa có tài liệu chính thức dành cho lớp Chuyên Tin khối THPT. Mà
chỉ tồn tại ở dưới dạng tên chuyên đề của Bộ Giáo dục gửi về cho các trường. Do vậy
việc dạy và học gặp nhiều khó khăn trong việc thống nhất về nội dung cũng như mức
độ về kiến thức chuyên môn. Nên việc nghiên cứu và xây dựng chuyên đề này là thực
sự cần thiết.
Mục đích của chuyên đề là truyền tải một cách tổng quát, chi tiết và sự thống
nhất về mặt nội dung để người đọc dễ hiểu và thấy được tầm quan trọng của bài toán
liệt kê tổ hợp và một số bài tập ứng dụng trong Tin học dành cho học sinh chuyên tin
ở trường THPT.
Nội dung của chuyên đề đã được các tác giả chọn lọc qua chương trình đã thực
dạy tại trường và tham khảo của một số đồng nghiệp khác trong nước.
Kiến thức là vô hạn, trong chuyên đề này chúng tôi đã có gắng sáng tạo, sưu
tầm và trao đổi một cách tốt nhất có thể về mặt lý thuyết, các bài tập ứng dụng và các
bài tập trong các kỳ thi trong nước để tạo thành cuốn tài liệu hiệu quả dành cho giáo
viên và các em học sinh đam mê tin học chính thức làm tài liệu cho mình trong quá
trình học tập và nghiên cứu.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 88


THPT CHUYÊN BẮC GIANG

TÀI LIỆU THAM KHẢO


[1]. Nguyễn Đức Nghĩa, Nguyễn Tô Thành. Toán rời rạc, NXB ĐHQGHN,
2003
[2]. ThS.Trần Đức Huyên. Phương pháp giải các bài toán trong Tin học.
NXBGD. 2004
[3]. Nguyễn Xuân Huy. Sáng tạo trong thuật toán và lập trìng. NXBGD. 2007.
[4]. Lê Minh Hoàng. Giải thuật và lập trình – A.D.A DSAP Textbook,
DHSPHN, 1999-2002. <Internet>
[5]. Trần Tuấn Minh. Thiết kế và đánh giá thuật toán. Đà lạt. <Internet>
[6]. Lê Minh Hoàng. Bài giảng các chuyên đề.
[7]. PGS. TS. Bài tập lập trinh Turbo Pascal 7.0
[8]. Robert Sedgewick. Cẩm nang thuật toán. tập 1,2. NXB Khoa học Kỹ thuật.
Năm XB 1998.

Duyệt các cấu hình tổ hợp và ứng dụng Trang 89


THPT CHUYÊN BẮC GIANG

MỤC LỤC
MỞ ĐẦU .............................................................................................................................................. 1
PHẦN 1. LÝ THUYẾT TỔ HỢP ......................................................................................................... 2
I. SƠ LƯỢC VỀ TỔ HỢP ........................................................................................................... 2
1. Khái niệm ............................................................................................................................. 2
2. Các bài toán thường gặp ....................................................................................................... 2
II. NHẮC LẠI LÝ THUYẾT TẬP HỢP ...................................................................................... 2
1. Các khái niệm và ký hiệu ..................................................................................................... 2
2. Các phép toán trên tập hợp ................................................................................................... 3
III. CÁC NGUYÊN LÝ CƠ BẢN .............................................................................................. 3
1. Nguyên lí cộng ..................................................................................................................... 3
2. Nguyên lí nhân ..................................................................................................................... 4
3. Nguyên lí bù trừ .................................................................................................................... 6
4. Nguyên lí Dirichlê ................................................................................................................ 7
IV. MỘT SỐ CẤU HÌNH TỔ HỢP THƯỜNG GẶP ................................................................ 8
1. Hoán vị ................................................................................................................................. 8
2. Chỉnh hợp lặp chập k của n phần tử ..................................................................................... 8
3. Chỉnh hợp không lặp chập k của n phần tử .......................................................................... 9
4. Tổ hợp k của n phần tử ......................................................................................................... 9
PHẦN 2. PHƯƠNG PHÁP SINH ...................................................................................................... 12
I. Khái niệm ............................................................................................................................... 12
II. Áp dụng phương pháp sinh vào giải một số bài toán ............................................................. 13
1. Bài toán 1: Liệt kê tất cả các dãy nhị phân có độ dài N. .................................................... 13
2. Bài toán 2: Liệt kê các tập con m phần tử của tập n phần tử.............................................. 14
3. Bài toán 3: Liệt kê các hoán vị của tập n phần tử. ............................................................. 17
4. Bài toán 4: Phân tích số nguyên dương N thành tổng các số nguyên không âm. .............. 19
PHẦN 3. GIẢI THUẬT QUAY LUI ................................................................................................. 23
1. Ý tưởng ............................................................................................................................... 23
2. Thuật toán quay lui ............................................................................................................. 26
3. Các ví dụ ............................................................................................................................. 30
4. Tài liệu tham khảo. ............................................................................................................. 49
PHẦN IV. ỨNG DỤNG ..................................................................................................................... 52
I. KHÁI NIỆM BÀI TOÁN TỐI ƯU. ....................................................................................... 52
1. Một số khái niệm ................................................................................................................ 52
2. Một số phương pháp giải bài toán tối ưu tổ hợp ................................................................ 55
II. PHƯƠNG PHÁP DUYỆT GIẢI BÀI TOÁN TỐI ƯU ......................................................... 56
1. Tư tưởng chủ đạo ................................................................................................................ 56
2. Cấu trúc của phương pháp duyệt tổng quát ........................................................................ 56
III. BÀI TẬP ÁP DỤNG .......................................................................................................... 58
KẾT LUẬN ........................................................................................................................................ 88
TÀI LIỆU THAM KHẢO .................................................................................................................. 89
MỤC LỤC .......................................................................................................................................... 90

Duyệt các cấu hình tổ hợp và ứng dụng Trang 90

You might also like