8/29/2016
BÀI 3
BÀI TOÁN LIỆT KÊ
Giáo viên: TS. Nguyễn Văn Hiệu
Email:
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
1
1.1. Giới thiệu
Nội dung
1.1. Giới thiệu
1.2. Phương pháp sinh
1.3. Phương pháp quay lui
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
2
1
8/29/2016
1.1. Giới thiệu
Mục đích
Đưa ra danh sách tất cả các cấu hình có
thể có
Bản chất
Xác định một thuật toán để theo đó có
thể lần lượt xây dựng được tất cả các
cấu hình đang quan tâm.
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
3
1.1. Giới thiệu
Nguyên tắc
Không được lặp lại một cấu hình
Không được bỏ sót một cấu hình
Lưu ý
Chỉ giải với bài toán chưa có phương
pháp giải
Phương pháp Sinh
Phương pháp quay lui
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
4
2
8/29/2016
1.2. Phương pháp sinh
Thường sử dụng
Giải bài toán liệt kê tổ hợp
Điều kiện
Xác định được một thứ tự.
Có cấu hình đầu tiên
Có cấu hình cuối cùng
Xác định được thuật toán để xây dựng
cấu hình kế tiếp
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
5
1.2. Phương pháp sinh
Bản chất
Chú thích
Generating_method(…) {
<Cấu hình ban đầu>;
stop = islastconfigure(…);
while (stop==0) {
<Cấu hình hiện thời >
<Sinh_kế_tiếp>;
}
}
Stop = =1, là cấu hình
cuối cùng
Stop == 0, chưa phải
là cấu hình cuối cùng
<Sinh_kế_tiếp> là
thuật toán sinh cấu
hình tiếp theo trên thứ
tự đã xác định trước
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
6
3
8/29/2016
1.2. Phương pháp sinh
Ví dụ
Liệt kê dãy nhị phân có độ dài n.
Liệt kê các tập con k phần tử của tập
n phần tử.
Liệt kê các hoán vị của tập n phần tử
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
7
1.2. Phương pháp sinh
Ví dụ 1:
Liệt kê các dãy nhị phân có độ dài n
Bước 1: Xác định thứ tự
nhị phân được biểu diễn:
b = (b1 b2 … bn )
thỏa mản bi €{0,1}
Định nghĩa thứ tự từ điển:
b = (b1 b2 ... bn) và *b = (*b1 *b2 ... *bn)
thứ tự b < *b,
nếu q(b) < q(*b)
Dãy
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
8
4
8/29/2016
1.2. Phương pháp sinh
Ví dụ 1:
Liệt kê các dãy nhị phân có độ dài n
Bước 2: Cấu hình đầu
và cuối
Khi n = 4 phần tử, có 24
dãy nhị phân được liệt kê
9
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
1.2. Phương pháp sinh
Ví dụ 1:
Liệt kê các dãy nhị phân có độ dài n
Bước 2:
b
0000
0001
0010
0011
0100
0101
0110
0111
q(b)
0
1
2
3
4
5
6
7
b
1000
1001
1010
1011
1100
1101
1110
1111
q(b)
8
9
10
11
12
13
14
15
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
10
5
8/29/2016
1.2. Phương pháp sinh
Bước 3: xác định thuật
toán
0000
0001
0001
0010
0011
0100
0111
1000
Thuật toán
Tìm i từ bên phải:
bi = 0.
Gán lại bi = 1 và
bj = 0 với mọi j> i.
i= n;
while (i>=1 && b[i]==‘1’)
b[i--] = ‘0’;
b[i] = ‘1’;
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
11
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
12
6
8/29/2016
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
13
1.2. Phương pháp sinh
Ví dụ 1:
Liệt kê các dãy nhị phân có độ dài n
Kết quả
Chương trình
Result
Source Code
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
14
7
8/29/2016
1.2. Phương pháp sinh
Ví dụ 2
Liệt kê các tập con k phần tử của tập n phần tử
Chuẩn bị
Ánh xạ tập n phần tử vào tập
X = {1,2,…,n}
Mỗi tập con k phần tử của X được biểu diễn bởi
bộ có thứ tự gồm k thành phần:
a = (a1 a2 a3 ..... ak )
thỏa mản 1≤ a1< a2 < a3 <..... < ak ≤ n
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
15
1.2. Phương pháp sinh
Ví dụ 2
Liệt kê các tập con k phần tử của tập n phần tử
Bước 1: Xác định thứ tự
Định nghĩa thứ tự từ điển:
a = (a1 a2 a3 ...ak) và b = (b1 b2 b3 ... bk)
thứ tự a < b, nếu tồn tại j (1≤ j≤ k):
a1 = b1,...,aj-1= bj-1, aj < bj
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
16
8
8/29/2016
1.2. Phương pháp sinh
Ví dụ 2:
Liệt kê các tập con k phần tử của tập n phần tử
Bước 2:
Các tập con 3 phần tử
của tập 5 phần tử
{1,2,3,4,5}
𝑪𝟑 5 = 10
{ 1,2,3 }
{ 1,2,4 }
{ 1,2,5 }
{ 1,3,4 }
{ 1,3,5 }
{ 1,4,5 }
{ 2,3,4 }
{ 2,3,5 }
{ 2,4,5 }
{ 3,4,5 }
Cấu hình đầu
Cách sinh
Cấu hình cuối
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
17
1.2. Phương pháp sinh
Bước 3: xác định
thuật toán
i=
1 2 3
= {1, 4, 5 }
n-k+i =
3 4
{ 2, , }
{ 2, 3, 4}
Giả sử a = (a1...ak ) không là
cuối cùng.
B1: Tìm vị trí i đầu tiên từ
bên phải của dãy:
ai ≠ n-k+i.
B2: Thay ai bởi ai + 1.
B3: Thay aj bởi ai - i +j,
với j = i+1,...,k
n=5, k=3
a
Thuật toán
5
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
18
9
8/29/2016
1.2. Phương pháp sinh
Thuật toán
Code
Giả sử a = (a1...ak ) không là
cuối cùng.
B1: Tìm vị trí i đầu tiên từ
bên phải của dãy:
ai ≠ n-k+i.
B2: Thay ai bởi ai + 1.
B3: Thay aj bởi ai - i +j,
với j = i+1,...,k
B1:
i=k;
while (a[i]==n-k+i) i-- ;
B2:
a[i]= a[i] + 1;
B3:
for (j=i+1;j<=k;j++)
a[j]= a[i]+ j –i;
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
19
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
20
10
8/29/2016
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
21
1.2. Phương pháp sinh
Ví dụ 2
Liệt kê các tập con k phần tử từ tập n phần tử
Kết quả
Chương trình
Result
Source Code
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
22
11
8/29/2016
1.2. Phương pháp sinh
Ví dụ 3
Liệt kê hoán vị của tập n phần tử
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
23
1.2. Phương pháp sinh
Minh họa
{1,2,3,4}
{1,2,4,3}
{1,3,2,4}
{1,3,4,2}
{1,4,2,3}
{1,4,3,2}
{2,1,3,4}
{2,1,4,3}
{2,3,1,4}
{2,3,4,1}
{2,4,1,3}
{2,4,3,1}
{3,1,2,4}
{3,1,4,2}
{3,2,1,4}
{3,2,4,1}
{3,4,1,2}
{3,4,2,1}
{4,1,2,3}
{4,1,3,2}
{4,2,1,3}
{4,2,3,1}
{4,3,1,2}
{4,3,2,1}
{1,2,3,4} ?
{4,3,2,1}?
{3,4,2,1} {4,1,2,3}?
Xây dựng thuật toán
sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
24
12
8/29/2016
1.2. Phương pháp sinh
Định nghĩa
Định nghĩa
Ánh xa tập n phần tử bất kỳ
vào tập
X = {1,2,…,n}
Mỗi hoán vị của X được
biểu diễn bởi bộ có thứ tự
gồm n thành phần:
a = (a1 a2 ... an )
thỏa mản ai € X,
i=1,…,n , ap ≠ aq , p ≠ q.
Thứ tự từ điển:
a = (a1 a2 a3 ...an)
b = (b1 b2 b3 ... bn)
thứ tự a < b,
nếu tồn tại j (1≤ j≤ n):
a1 = b1,...,aj-1= bj-1, aj < bj
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
25
1.2. Phương pháp sinh
Bước 3:
Thuật toán
n= 4
i=
a
k =
1 2 34
= {1 3 4 2}
1
2 3 4
a =
{ 1 3 4 2}
a =
{ , 4 , 3, }
a =
{ , , 2, 3 }
a = (a1 a2...an ) chưa phải là cuối
cùng.
B1: Tìm Right -> Left, j đầu
tiên:
aj ≤ aj+1
B2: Tìm Right -> Left, k đầu
tiên:
ak > aj.
B3: hoán vị aj và ak
B4: Lật ngược đoạn aj+1 đến an
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
26
13
8/29/2016
1.2. Phương pháp sinh
Bước 3:
B1: Tìm Right -> Left, j
đầu tiên:
aj ≤ aj+1
B2: Tìm Right -> Left, k
đầu tiên:
ak > aj.
B3: hoán vị aj và ak
B4: Lật ngược đoạn aj+1
đến an
int j = n-1;
while(a[j]>a[j+1])j--;
int k = n;
while(a[j]>=a[k])k--;
int temp = a[j];
a[j] = a[k]; a[k] = temp;
int l = j+1;int r = n;
while(l
int temp = a[l];
a[l]= a[r]; [r]= temp;
l++;
r--;
}
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
27
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
28
14
8/29/2016
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
29
1.2. Phương pháp sinh
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
30
15
8/29/2016
1.2. Phương pháp sinh
Ví dụ 2
Liệt kê các tập hoán vị của tập n phần tử
Kết quả
Chương trình
Result
Source Code
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
31
Bài toán liệt kê
Nội dung
1.1. Giới thiệu
1.2. Phương pháp sinh
1.3. Phương pháp quay lui
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
32
16
8/29/2016
Phương pháp quay lui
Nội dung
Mục đích
Khái niệm
Phương pháp
Mã giả
Minh họa
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
33
1.3. Phương pháp quay lui
Mục đích
Khái niệm
Để giải bài toán liệt kê
hoặc tối ưu tổ hợp
Đã giải:
Bài toán mã đi tuần
Bài toán xếp hậu
Bài toán mê cung
Bài toán người giao
hàng
Backtracking
Поиск с возвратом
Quay lui
Backtracking
1950,
D.H.Lehmer
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
34
17
8/29/2016
1.3. Phương pháp quay lui
Khái niệm
Khái niệm
Backtracking– đi tìm lời
giải cho bài toán mà
nghiệm của nó là một cấu
hình hoặc một tập cấu
hình:
Tính chất P: xác định
cấu hình
Tính chất Q: xác định
tính dừng của bài toán
Một cấu hình hay một nghiệm:
s 1 s 2… s n
si ∈D
Bài toán:
Liệt kê tất cả các cấu hình của S
S=
s 1 s 2… s n
Bài toán con:
Giả sử đã tìm được s 1… s i , i < 𝑛
Hãy tìm cấu hình S
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
35
1.3. Phương pháp quay lui
Phương pháp
Bản chất
Giả sử có: s1…s i-1
Tìm giá trị cho s i:
Một quy trình tìm kiếm theo chiều
sâu
Duyệt ∀ j ∈ 𝐷 đề cử cho si
Mỗ𝑖 j ∈ 𝐷 kiểm tra:
Nếu j chấp nhận (∈ P ), si = j
Nếu i = n (∈ Q ) , được 1
cấu hình,
Nếu i< 𝑛, tìm s i + 1.
Nếu ∀ j không được cấp nhận
(∉ P ) (ngõ cụt) thì quay lại
bước xác định si-1
Ví dụ tìm số có 3 chữ số đầu tiên
D = {1,2, 3}
P:
(2,1,3) – chấp nhận
(2,2,3) – không chấp nhận
123
132
213
231
312
321
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
36
18
8/29/2016
1.3. Phương pháp quay lui
Phương pháp
Giả sử có: s1…s i-1
Tìm giá trị cho s i:
Mã giả
void try (i, n){
Duyệt ∀ j ∈ 𝐷 đề cử cho si
Mỗ𝑖 j ∈ 𝐷 kiểm tra:
Nếu j chấp nhận (∈ P ), si = j
Nếu i = n (∈ Q ) , được 1
cấu hình,
Nếu i< 𝑛, tìm s i +1.
Nếu ∀ j không được cấp nhận
(∉ P ) (ngõ cụt) thì quay lại
bước xác định si-1
∀j ∈ Di{
if (< chấp nhận j>){
si = j;
if (i==n)
<Ghi cấu hình S>
else try (i+1, n);
}
}
}
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
38
1.3. phương pháp quay lui
Bắt đầu
S1
D1 ( 2pt)
s2
D2 (2pt)
s3
D3 (2pt)
D4 ( 3pt)
s4
Một cấu
hình
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
39
19
8/29/2016
1.2. Phương pháp quay lui
Ví dụ
Liệt kê dãy nhị phân có độ dài n.
Liệt kê hoán vị tập n phần tử.
Bài toán Xếp Hậu.
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
40
1.3. Phương pháp quay lui
Ví dụ 1
Liệt kê xâu nhị phân độ dài n
Biểu diễn dãy nhị phân:
b = ( b1 b2... bn ,)
bi ∈ {0,1}
Try(i,…) - xác định bi
D = {0,1}
P
i = n - được 1 cấu hình ∈ 𝑄
Mã giả
void Try(int i, char b[]){
char j;
for(j='0'; j<='1';j++){
//P – bỏ qua kiêm tra
b[i]=j;
if(i==n) Out(b);
else Try(i+1,b);
}
}
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
41
20
8/29/2016
1.3. Phương pháp quay lui
Bit 1
2
3
4
0
0
0
0 0000
1 0001
Try(1,b)
1
0 0010
1 0011
1
0
0 0100
1 0101
1
0 0110
1 0111
1
0
0
0 1000
1 1001
1
0 1010
1 1011
1
0
0 1100
Mã giả
void Try(int i, char b[]){
char j;
for(j='0'; j<='1';j++){
//P – bỏ qua kiêm tra
b[i]=j;
if(i==n) Out(b);
else Try(i+1,b);
}
}
1 1101
1
0 1110
1 1111
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
42
1.3. Phương pháp quay lui
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
43
21
8/29/2016
1.2. Phương pháp quay lui
Ví dụ 1
Liệt kê xâu nhị phân độ dài n
Kết quả
Chương trình
Source Code
Result
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
44
1.3. Phương pháp quay lui
Ví dụ 2
Ví dụ 2
Liệt kê các hoán vị của tập
X = {1,2,…,n}.
Sử dụng mảng b
b = { b[1], b[2],…, b[n]}
Biểu diễn hoán vị dạng
s1 s2 ... sn
si ∈ X , sp ≠ sq , p ≠ q.
Try(i,…) - xác định si
D = {1,…,n}
Chấp nhận j ∈ 𝐷 nếu j chưa
được chọn.
b[j] =
1 , 𝑗 𝑐ℎư𝑎 𝑐ℎọ𝑛
0 , 𝑗 đã đượ𝑐 𝑐ℎọ𝑛
Khởi tạo b[j] = 1, ∀𝑗 ∈ 𝐷
i = n - được 1 cấu hình ∈ 𝑄
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
45
22
8/29/2016
1.3. Phương pháp quay lui
Ví dụ 2
Mã giả
Liệt kê các hoán vị của tập
X = {1,2,…,n}.
void Try(int i,int b[],int s[]){
int j;
for(j=1;j<=n;j++){
if(b[j]==1){
s[i]=j;
b[j]=0;
if(i==n) Out(s);
else Try(i+1,b,s);
b[j]=1;
}}
}
Biểu diễn hoán vị dạng
s1 s2 ... sn
si ∈ X , sp ≠ sq , p ≠ q.
Try(i,…) - xác định si
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
46
1.3. Phương pháp quay lui
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
47
23
8/29/2016
1.3. Phương pháp quay lui
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
48
1.2. Phương pháp sinh
Ví dụ 2
Liệt kê hoán vị của tập n phần tử
Kết quả
Chương trình
Result
Source Code
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
49
24
8/29/2016
1.3. Phương pháp quay lui
Ví dụ 3
Ví dụ 3
Liệt kê tất cả các cách xếp 8
quân Hậu trên bàn cờ 8x8 sao
cho chúng không ăn được
nhau.
Đánh số cột từ 1.. 8
Đánh số hàng từ 1.. 8
Biểu diễn cách xếp:
x1 x2 … x8
xi được xếp ở hàng i
D = {1,…,8}
xi= j : Hậu thứ i được
xếp vào cột j
j được chấp nhận nếu ô
(i,j) được tự do
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
50
1.3. Phương pháp quay lui
Ví dụ 3
Ví dụ 3
Mảng a – quản lý cột
ô (i,j) được tự do
a = { a[1], …, a[8]}
Quản lý cột
Quản lý đường chéo thuận
1 , 𝑐ộ𝑡 𝑗 𝑡ự 𝑑𝑜
Quản lý đường chéo
a[j] =
0
, 𝑐ộ𝑡 𝑗 đã 𝑐ℎ𝑖ế𝑢
nghịch
Nguyễn Văn Hiệu, 2012, Discrete Mathematics
51
25