You are on page 1of 52

Một số vấn đề cơ sở

của Tin học


Buổi 3:
Cấu trúc dữ liệu và thuật giải

Giáo viên: Tạ Thúc Nhu


Khoa CNTT trường ĐH Lạc Hồng
ĐỆ QUI
RECURVE

2 Mã hóa
Khái niệm Đệ Qui

Một đối tượng được gọi là đệ qui nếu nó hoặc 1 phần của nó
được định nghiã thông qua khái niệm về chính nó.
Ví dụ: Định nghiã phép toán giai thừa, ký hiệu: N!
• (a) Nếu N = 0, thì N! = 1
• (b) nếu N > 0 thì N! = N*(N-1)!
Ví dụ: Định nghiã UCLN của 2 số x và y, ký hiệu: UCLN(x, y)
• (a)UCLN(x,y) = x nếu y = 0
• (b)UCLN(x,y) = UCLN(y, phần dư của x/y) nếu y<>0

3 Mã hóa
Chương trình đệ qui

• Một chương trình là đệ qui nếu trong chương trình có lời


gọi đến chính nó.
Ví dụ: Định nghĩa hàm tính N! theo đệ qui.
int GiaiThua(int N)
{
if (N == 0) return 1;
return N * GiaiThua(N - 1);
}

4 Mã hóa
Một định nghiã đệ qui phải có 2 thành phần:

• Thành phần dừng: Không chứa khái niệm đang định nghiã
Ví dụ: N! = 1
• Thành phần đệ qui: có chứa khái niệm đang định nghiã

5 Mã hóa
Ví dụ: Tính UCLN(x,y) theo thuật toán Euclide
• (a)UCLN(x,y) = x nếu y = 0
• (b)UCLN(x,y) = UCLN(y, phần dư của x/y) nếu y<>0

int UCLN(int x, int y)


{
if (y == 0) return x;
return UCLN(y, x % y);
}

6 Mã hóa
THUẬT GIẢI QUAY LUI
BACK TRACKING

7 Mã hóa
Tổng quan thuật giải Quay lui (Back Tracking)

• Dùng giải bài toán liệt kê các cấu hình


• Mỗi cấu hình được xác định bằng cách xây dựng tuần tự từng thành
phần trong cấu hình.
• Mỗi thành phần được xác định bằng cách chọn lựa dữ liệu trong tập khả
năng được đề xuất.

Cấu hình một lời giải X1 X2 X3 … Xn

Tập khả năng K1 K2 … … Km

8 Mã hóa
Mô hình thuật giải quay lui:
Xác định phần tử Xi bằng đệ quy
void Try( int i )
{
If (Xi là phần tử cuối cùng trong cấu hình)
< Thông báo cấu hình tìm được>;
else
for ( mọi Kj thuộc tập khả năng đề cử cho Xi)
[ if ( Chấp nhận Kj ) ]
{
Thử chọn Kj cho Xi;
Try( i+1); //Gọi đệ quy để xác định phần tử Xi+1
Bỏ ghi nhận Kj đã chọn cho Xi để chọn khả năng khác;
}
}

9 Mã hóa
Hai điểm mấu chốt quyết định độ phức tạp của bài toán là:
1. Xác định tập khả năng đề cử: Phụ thuộc vào việc phân tích
nhu cầu dữ liệu của từng thành phần trong cấu hình
2. Kiểm tra khả năng đề cử phải phù hợp với thành phần cần
xác định.

10 Mã hóa
Bài toán: Liệt kê các dãy nhị phân có độ dài n
Phân tích:
• Biểu diến cấu hình dãy nhị phân dưới dạng: X[1..n]
• Tập khả năng đề cử cho mỗi phần tử Xi là {0, 1}
• Thuật giải xác định phần tử Xi của dãy nhị phân như sau:
void Try(int i)
{
if ( i > n ) <Thông báo cấu hình tìm được>;
else
for (int j =0; j<= 1; j++)
{
X[ i ] = j;
Try( i + 1 );
}
}
11 Mã hóa
Mã đi tuần: chỉ ra hành trình của quân Mã xuất phát
từ một ô trên bàn cờ đi qua tất cả các ô còn lại của
bàn cờ, mỗi ô đúng 1 lần.
Phân tích:
• Cấu hình lời giải là BC[1..n][1..n]
chứa số thứ tự hành trình của 2
(u, v)
quân Mã.
• Tập khả năng chứa các giá trị
dùng tính tọa độ các ô kế tiếp 1
(x, y)
dx[1..8] = {-2,-1, 1, 2, 2, 1, -1, -2}
dy[1..8] = { 1, 2, 2, 1, -1, -2, -2, -1}
• Điều kiện chọn khả năng cho
bước đi thứ i là Ô được chọn
phải :
– Thuộc bàn cờ
– Và chưa đi qua

12 Mã hóa
Thuật giải xác định bước đi thứ i của quân Mã
void Try(int i)
{ int j,u,v;
if (i > n*n) <Thông báo cấu hình tìm được>;
else
for ( j =1; j <= 8 ; j++)
{
u =x+dx[j]; v = y+dy[j];
if (u >= 1 && u <= n && v >= 1 && v<=n && BC[u,v] = 0)
{
x = u; y = v;
BC[u,v] = i;
Try(i+1);
x = u-dx[j]; y = v-dy[j];
BC[u,v] = 0;
}
}
}

13 Mã hóa
Bài toán:
Liệt kê các hoán vị của dãy số {1, 2, .., n}

• Biểu diễn cấu hình một hoán vị: X[1..n]


• Tập khả năng đề cử: { 1, 2, .., n }
• Nhưng do Xi <> Xj với i <> j. Nên phải kiểm tra giá trị đề cử
cho Xi phải khác với các giá trị đã chọn cho các thành phần
trước đó.
Hướng giải quyết chung là tổ chức các biến trạng thái lưu
trữ thông tin phục vụ cho việc kiểm tra:
Dùng mảng F[1..n] để ghi nhớ tình trạng sử dụng của từng
khả năng trong tập S={1, 2, .., n}, với qui ước:
F[ j ] = 0 nếu j chưa sử dụng
F[ j ] = 1 nếu j đã sử dụng

14 Mã hóa
Thuật giải xác định phần tử Xi của một hoán vị

void Try(int i)
{ if ( i > n ) <Thông báo cấu hình tìm được>;
else
for (int j = 1; j<= n; j++)
if (F[j] = 0)
{
X[i] = j;
F[j] = 1;
Try( i + 1 );
F[j] = 0;
}
}

15 Mã hóa
Ví dụ: Liệt kê các tập con k phần tử
của tập S = {1, 2, .., n}. Trong đó (k <= n)

• Biểu diễn cấu hình một tập con K phần tử: X[1..K]
• Tập khả năng đề cử: { 1, 2, .., n }
• Nhưng do Xi <> Xj với i <> j. Nên các giá trị đề cử cho Xi
phải khác với các giá trị đề cử cho các thành phần trước đó
Hướng giải quyết:
Dùng mảng F[1..N] để ghi nhớ tình trạng sử dụng của từng
khả năng trong tập S={1, 2, .., N}, với qui ước:
F[ j ] = 0 nếu j chưa sử dụng
F[ j ] = 1 nếu j đã sử dụng

16 Mã hóa
Thuật giải xác định phần tử Xi của một tập con

void Try(int i)
{ if ( i > K ) <Thông báo cấu hình tìm được>;
else
for (int j = 1; j<= N; j++)
if (F[j] = 0)
{
X[i] = j;
F[j] = 1;
Try( i + 1 );
F[j] = 0;
}
}

17 Mã hóa
Một cách giải khác của bài toán tập con

Đưa ra điều kiện cho mỗi tập con là :


1 <= X[1] < X[2] < .. < X[ i ] < .. < X[K-1] < X[K] <= N
• Nhận xét:
X[K] <= N
X[K-1] <= X[K] - 1 <= N - 1

X[ i ] = X[K-(K-i)] <= N - (K - i)
• Do đó, ta có thể giới hạn giá trị đề cử cho thành phần X[i]
trong khoảng từ : X[i-1]+1 đến (N – K + i)
• Để điều này cũng đúng cho cả trường hợp i = 1, ta thêm vào
X[0] = 0.

18 Mã hóa
Thuật giải xác định phần tử Xi của một tập con

void Try(int i)
{
if ( i > K ) <Thông báo cấu hình tìm được>;
else
for (int j = X[i-1]+1; j<= N-K+i; j++)
{
X[i] = j;
Try( i + 1 );
}
}

19 Mã hóa
KỸ THUẬT NHÁNH CẬN

20 Mã hóa
Công dụng

• Dùng giải quyết bài toán tìm cấu hình tốt nhất trong các cấu
hình liệt kê bằng thuật toán quay lui.
• Giảm thời gian thực hiện của thuật toán quay lui.
Kỹ thuật nhánh cận thêm vào cho thuật toán quay lui khả năng đánh
giá cấu hình ở từng bước.
Nếu tại bước thứ i đánh giá được cấu hình không tối ưu thì quay lui
ngay không cần phải gọi đệ quy tìm tiếp các thành phần khác của cấu
hình.

21 Mã hóa
Mô hình đánh giá nhánh cận
trong thuật toán quay lui:
// Khởi tạo cấu hình BESTCONFIG xấu nhất
void Init()
{
<Khởi tạo một cấu hình BESTCONFIG xấu nhất>
}
//Mô hình thuật toán quay lui xác định X[i] có đánh giá nhánh cận
void Try( int i )
{
If (Xi là phần tử cuối cùng trong cấu hình)
<Cập nhật BESTCONFIG>;
else
for ( mọi Kj thuộc tập khả năng đề cử cho Xi)
[ if ( Chấp nhận Kj ) ]
{
Thử chọn Kj cho Xi;
if (còn hy vọng tìm ra cấu hình tốt hơn BESTCONFIG) Try( i+1);
Bỏ ghi nhận Kj đã chọn cho Xi để chọn khả năng khác;
}
}
22 Mã hóa
Bài toán người du lịch

Có n thành phố (được đánh số từ 1 đến n). Một người đi du lịch xuất phát từ
một thành phố muốn đi thăm các thành phố khác, mỗi thành phố đúng một lần
rồi quay về nơi xuất phát. Giả thiết biết được chi phí đi từ thành phố i đến thành
phố j là C[i,j], 1≤ i, j < n.
Hãy tìm 1 hành trình cho người du lịch để tổng chi phí theo hành trình này là ít
nhất.

2
1 3 0 3 2 1
3 3 0 1 2
1
1 2 1 0 4
2
1 2 4 0
2 4
4 Ma trận chi phí C

23 Mã hóa
Phân tích:

• Cấu hình lời giải : X[1..n]


– X[1] = 1 được xem là thành phố xuất phát.
– Một hành trình là một hoán vị của các thành phố 2, .. ,n.
• Tập khả năng đề cử : {2, 3,.., n}
• Cấu hình BESTCONFIG:
– Smin là tổng chi phí thấp nhất đã chọn trong các hành trình tìm
được. Khởi tạo ban đầu cho Smin = Cmax * (n + 1), trong đó Cmax
là chi phí lớn nhất trong các chi phí C[i, j] đã cho
– BestWay[1..n] : chứa hành trình có chi phí thấp nhất.

24 Mã hóa
• Các vấn đề cần thực hiện khi xác định thành phần X[i]:
1. Kiểm tra khả năng đề cử cho thành phần X[i] hợp lệ: khả năng đó
chưa được chọn cho các thành phần trước X[i].
2. Ghi nhận tổng chi phí cho hành trình từ X[1] đến X[i].
3. Dự đoán cấu hình lời giải tốt hơn hay xấu hơn BESTCONFIG

25 Mã hóa
2- Ghi nhận tổng chi phí
cho hành trình từ X[1] đến X[i]

• Mảng T[1..n] ghi nhận tổng chi phí tại mỗi bước
• T[i] chứa tổng chi phí cho hành trình từ X[1] đến X[i]
• Nếu thành phố j được đề cử cho thành phần X[i] thì:
T[i] = T[i-1] + C[X[i-1], j]
• Tổng chi phí của hành trình từ X[1] đến X[n] và trở về X[1]
là: T[n] + C[X[n], 1]
2
1 3
3
1
1
2

2 4
4

26 Mã hóa
3- Dự đoán cấu hình lời giải
tốt hơn hay xấu hơn BESTCONFIG

• Gọi Cmin là chi phí thấp nhất trong các chi phí C[i, j] đã cho.
• Sau khi xác định X[i], nếu đi tiếp (n – i +1) thành phố nữa thì chi
phí tối thiểu phải là T[i] + Cmin*(n-i+1).
• Nếu T[i] + C[i,j]*(n-i+1) < Smin thì có khả năng tìm được hành
trình tốt hơn BESTCONFIG, ngược lại thì hành trình tìm được
sẽ không tốt hơn BESTCONFIG.

27 Mã hóa
Thuật giải xác định thành phần X[i]

void Try(int i)
{ if ( i > n )
if ( T[n] + C[x[n] , 1] < Smin )
{
Smin = T[n] + C[x[n] , 1];
Ghi nhận X là hành trình tốt nhất: Bestway = X;
}
else
for (int j = 2; j <= n; j++)
if (F[ j ] = 0)
{
X[ i ] = j; F[ j ] = 1;
T[ i ] = T[i -1] + C[ x[i -1], j];
if ( T[ i ] + (n-i+1)*Cmin < Smin) Try( i + 1 );
F[ j ] = 0;
}
}
28 Mã hóa
Bài toán chuỗi 123

Tìm một chuỗi có độ dài n (n <= 100) chỉ gồm các số 1, 2, 3


thỏa mãn điều kiện:
1. Hai chuỗi con bất kỳ liền nhau đều khác nhau
2. Có ít số 3 nhất

Ví dụ: n = 9. Chuỗi nào sau đây hợp lệ?


131213212
123212313
123212321

29 Mã hóa
Phân tích

• Cấu hình lời giải: X[1..n]


• Tập khả năng đề cử: { 1, 2, 3 }
• Cấu hình BESTCONFIG:
1. Min3: chứa số lượng số 3 ít nhất. Khởi tạo Min3 = n
2. BestStr[1..n]: chứa chuỗi có số lượng số 3 ít nhất.

30 Mã hóa
• Các vấn đề cần thực hiện khi xác định thành phần X[i]:
1. Kiểm tra khả năng đề cử cho thành phần X[ i ] hợp lệ: nghĩa là
chuỗi X[1..i] không có 2 chuỗi con liền kề giống nhau.
2. Ghi nhận số lượng số 3 có trong chuỗi X[1..i]
3. Dự đoán cấu hình lời giải tốt hơn hay xấu hơn BESTCONFIG

31 Mã hóa
1- Kiểm tra chuỗi X[1..i] không có 2 chuỗi con
liền kề giống nhau.
Ví dụ: int ChuoiHopLe(int i)
123212321 {
123212321 for (L = 1; L <= i / 2; L++)
123212321 if ( X[(i–L+1) .. i] = X[(i–2L+1) .. (i- L)] )
123212321 return 0;
123212321 return 1;
}

32 Mã hóa
2- Ghi nhận số lượng số 3 trong chuỗi X[1..i]

• Mảng T[1..n] ghi nhận số lượng số 3 tại mỗi bước


• T[i] chứa số lượng số 3 trong chuỗi X[1..i ]
• Nếu giá trị đề cử là 3 thì T[i] = T[i-1] +1,
ngược lại thì T[i] = T[i-1]

33 Mã hóa
3- Dự đoán cấu hình lời giải
tốt hơn hay xấu hơn BESTCONFIG
131213212 Do 2 chuỗi con kề phải khác nhau nên:
131213212 • Trong 4 số liên tiếp phải có một số 3.
131213212 • Do đó, một dãy con có độ dài là k phải có ít nhất (k / 4) số 3.
131213212 • Sau khi xác định thành phần X[i] và ghi nhận số lượng số 3
trong T[i], ta còn (n – i) thành phần cần xác định.
131213212
• Do đó, cấu hình tìm được phải có ít nhất (T[i] + (n-i)/4) số
131213212 lượng số 3.
• Nếu (T[i] + (n-i)/4) < Min3 thì có khả năng tìm được cấu hình
tốt hơn BESTCONFIG, ngược lại thì cấu hình tìm được sẽ
không tốt hơn BESTCONFIG.

34 Mã hóa
Thuật giải xác định thành phần X[i]
void Try(int i)
{ if ( i > n )
{
Min3 = T[n];
Ghi nhận X là chuỗi tốt nhất: BestStr = X;
}
else
for (int j = 1; j <= 3; j++)
{
X[i] = j;
if (ChuoiHopLe( i ))
{
if (j == 3) T[i] = T[i -1] + 1;
else T[i] = T[i -1];
if ( T[ i ] + (n - i)/4 < Min3) Try( i + 1 );
}
}
}
35 Mã hóa
Giải thuật chia để trị
(Devide and conquer)

36 Mã hóa
Tổng quan giải thuật chia để trị

Kỹ thuật chia để trị bao gồm hai quá trình:


• Phân chia bài toán đã cho thành các bài toán con cùng loại,
lần lượt giải từng bài toán con đó một cách độc lập.
• Tổng hợp kết quả từ bài toán con để có lời giải của bài toán
ban đầu.

Thông thường, chia bộ dữ liệu đầu vào thành các phần riêng
rẽ, sau đó gọi 2 thủ tục đệ qui với bộ dữ liệu đầu vào là các
phần vừa chia.

37 Mã hóa
Một số bài toán tiêu biểu

• Tìm nhị phân


• QuickSort
• Nhân số nguyên lớn

38 Mã hóa
Tìm nhị phân trên mảng sắp thứ tự

Bài toán : Cho mảng A[1..n] được sắp xếp theo thứ tự không
giảm và x. Tìm i sao cho A[i] = x.
Phân tích:
Do mảng A sắp thứ tự tăng nên x:
• Hoặc là bằng phần tử nằm ở vị trí giữa mảng A
• Hoặc là nằm ở nửa bên trái (x<phần tử ở giữa mảng A )
• Hoặc là nằm ở nửa bên phải (x>phần tử ở giữa mảng A )

39 Mã hóa
Thuật giải: Tìm nhị phân trên mảng sắp thứ tự

int Bsearch(x, A[ ], int L, int R)


{
if (L > R) then return -1;
else
{
M = (L + R)/2;
If (x = A[M]) return M;
If (x < A[M]) return Bsearch(x, A, L, M-1)
return Bsearch (x, A, M+1, R)
}
}

40 Mã hóa
Bài toán tương tự:
Tìm đường đi cho xe có tải trọng lớn nhất
Có N thành phố, cho biết mỗi con đường nối từ thành phố i đến thành phố j
(với i <> j) có thể cho xe với trọng tải không quá C[i, j] đi qua.
Cho thành phố xuất phát x và thành phố đích y. Hãy tìm một đường đi từ
thành phố x tới thành phố y mà trọng tải lớn nhất có thể được.
Ý tưởng:
• Khởi tạo: Cmax = MAX{Cij} với mọi i khác j; Cmin =Min{Cij}
• Xét đoạn [ Cmin , Cmax]
1. Đặt Cm = (Cmax+Cmin) div 2.
2. Ta kiểm tra xem có tồn tại đường đi từ x tới y cho xe có trọng tải Cm hay
không?
a) Nếu tồn tại đường đi, ta ghi nhận kết quả và xét tiếp đoạn [Cm+1,Cmax].
b) Nếu không tồn tại đường đi, ta chuyển sang xét đoạn [Cmin ,Cm -1].
3. Lặp lại cho tới khi đoạn có giá trị đầu lớn hơn giá trị cuối.

41 Mã hóa
Thuật giải chọn lộ trình có tải trong lớn nhất
void Chon(int Cmin, int Cmax)
{
if (Cmin <= Cmax)
{
Cm = (Cmin + Cmax)/2;
d = 0; //Độ dài lộ trình
LoTrinh[0] = x; // Mảng ghi nhận lộ trình đi từ x đến y
if (TonTai(LoTrinh, d, x, Cm ) )
{
GhiNhan(LoTrinh, d, Cm);
Chon(Cm+1, Cmax);
}
else Chon(Cmin, Cm-1) ;
}
}
42 Mã hóa
Thuật giải kiểm tra tồn tại lộ trình cho xe
có tải trọng Cm đi qua
int TonTai(LoTrinh[ ], int &d, int i, int Cm)
{
int j;
if ( i = y ) return 1;
for (j = 0; j < n; j++)
if (F[ j ] = 0 && C[ i ][ j ] >= Cm)
{
F[ j ] = 1;
d++;
LoTrinh[d] = j;
if (TonTai(LoTrinh, d, j, Cm)) return 1;
d--;
F[ j ] = 0;
}
return 0;
}
43 Mã hóa
Bài toán tương tự

Cho N và S là 2 số nguyên dương.


Trong đó, N<= 100 và S <= 10100
Biết rằng căn bậc N của một số S là một số nguyên < 106.
Hãy tìm căn bậc N của S
Ví dụ:
S = 30517578125
N = 15
KQ = 5

44 Mã hóa
Thuật toán sắp xếp mảng Quick Sort
Ý tưởng thuật toán sắp xếp tăng cho dãy X[L .. R]
Bước 1: Phân chia dãy X[L .. R] thành 2 dãy con bằng cách:
– Chọn giá trị P của 1 phần tử trên dãy X[L .. R] làm mốc phân
hoạch.
– Đổi chổ các phần tử X[i]>= P với các phần tử X[j]<= P, với i < j
– Khi i > j, dãy ban đầu được phân thành 2 phần:
1. X[ L .. j ] chứa giá trị <= P
3. X[ j .. i ] chứa giá trị = P
2. X[ i .. R ] chứa giá trị >= P
Bước 2:
– Nếu X[L .. j] có hơn 1 phần tử thì sắp xếp tăng dãy X[L .. j]
– Nếu X[i .. R] có hơn 1 phần tử thì sắp xếp tăng dãy X[i .. R]
45 Mã hóa
Minh họa thuật toán
5 1 7 5 3 6 2 9
i j
2 1 7 5 3 6 5 9
i j

2 1 3 5 7 6 5 9
i=j
2 1 3 5 7 6 5 9
L j i R

2 1 3 7 6 5 9
1 2 3 5 6 7 9
L=j i=R L=j i R

7 9
7 9
j L i=R

1 2 3 5 5 6 7 9
46 Mã hóa
Thuật giải Quick Sort
void QuickSort(X[L .. R])
{
int i = L;
int j = R;
P = X[i];
while (i <= j)
{
while (X[i] < P) i++;
while (X[j] > P) j--;
if (i <= j)
{
if (X[i] <> X[j]) Hoanvi(X[i], X[j]);
i++; j--;
}
}
if (L < j) QuickSort(X[L ..j ]);
if (i < R) QuickSort(X[i .. R]);
}
47 Mã hóa
Nhân hai số nguyên X.Y có n chữ số
Phân tích:
• Chia X thành 2 số nguyên có n/2 chữ số: X=A.10n/2+B
• Chia Y thành 2 số nguyên có n/2 chữ số: Y=C.10n/2+D
X.Y = A.C.10n+(A.D+B.C)10n/2+B.D
Mặt khác: R = (A + B)(C + D) = A.C + A.D + B.C + B.D
A.D+B.C = R – A.C – B.D
Khi đó: X.Y = A.C.10n+(R-A.C-B.D)10n/2+B.D
• Phép nhân với 10n thực chất là thêm n chữ số 0
• 3 phép nhân số nguyên lớn n/2 chữ số :A.C, B.D, (A+B)(C+D)
tiếp tục được phân chia cho đến khi 2 toán hạng chỉ có một chữ
số.

48 Mã hóa
Ví dụ: nhân X=981 với Y=1234.

• Trước tiên chúng ta điền thêm vào toán hạng ngắn hơn các số 0 vô nghĩa để
làm cho hai toán hạng có cùng độ dài: 981 trở thành 0981.
• Sau đó tách từng toán hạng thành hai nửa:
X = 0981 cho ra A = 09 và B = 81 è 981 = A.102 + B
Y = 1234 thành C = 12 và D = 34 è 1234 = C.102 + D
• Do đó, tích cần tìm có thể tính được là:
P = A.C = 09 * 12 = 108
Q = B.D = 81 * 34 = 2754
R = (A + B)(C + D) = 90 * 46 = 4140
và cuối cùng
981 x 1234 = P.104 + (R – P – Q).102 + Q
= 1080000 + 127800 + 2754 = 1210554.

49 Mã hóa
Thuật giải: Nhân 2 số nguyên có n chữ số

SoLon Nhan(SoLon X, SoLon Y, int n)


{
If ( n = 1) return X*Y;
A=left(X,n/2);
B=right(X,n/2);
C=left(Y,n/2);
D=right(Y,n/2);
P = Nhan(A,C,n/2);
Q = Nhan(B,D,n/2);
R = Nhan(A+B,D+C,n/2);
return (P*10n +(R-P-Q)*10n/2 + Q);
}
50 Mã hóa
Một số bài toán buổi 3

1. Mỗi hột xí ngầu có 6 mặt, mỗi mặt chứa từ 1 đến 6 dấu chấm. Liệt kê các kết
quả phân biệt có thể có khi đổ cùng lúc 3 hột xí ngầu, không kể thứ tự xuất
hiện trên các hột xí ngầu, ví dụ {1, 2, 3} và {2, 3, 1} là như nhau.
2. Cho 1 mảng gồm n các số nguyên a[1], a[2],.., a[n] và một số nguyên S. Hãy tìm
tất cả các dãy con : 1 <= x1 < x2 < .. < xk <= n sao cho: a[x1] + a[x2] + ..+ a[xk] =
S
3. Tính số cách và in tất cả các cách phân tích số tự nhiên N >1 thành tổng các số
tự nhiên nhỏ hơn nó (mọi phân tích chỉ kể đúng một lần: 4+3+1 và 1+4+3 chỉ là
một)
4. Hãy tìm tập hợp các dấu '+’, ‘-‘ và không dấu giữa dãy số 123456789 sao cho
được một biểu thức có giá trị bằng = N cho trước. Ví dụ: N = 280 ta có các tổ
hợp sau: 1+2+345-67+8-9; 1+234-5+67-8-9; 123-4+5+67+89
5. Cho một dãy N số nguyên. Hãy loại bỏ khỏi dãy một số phần tử để được một
dãy con, có ít nhất 2 phần tử, không giảm và dài nhất. In ra dãy con đó.
Ví dụ: N = 10
2 6 -7 5 8 1 -3 5 15 9
Kết quả tìm được dãy con không giảm dài nhất có 4 phần tử:
-7 -3 5 9

51 Mã hóa
6. Trên bàn cờ ô vuông 4x4 xếp 8 quân cờ gồm 4 quân màu đen và 4 quân màu trắng sao
cho trên mỗi hàng và mỗi cột có đúng một quân màu đen và 1 quân màu trắng. Thể hiện
trên màn hình các cách sắp xếp này
7. Một người cha mang theo số tiền là M vào một cửa hàng để mua K món quà để tặng cho
các con. Trong cửa hàng có N mặt hàng, mặt hàng thứ i có giá tiền là Ai. Người cha cần
chọn K (K < N) mặt hàng khác nhau để làm quà sao cho tổng số tiền của K mặt hàng này
không lớn hơn số tiền mang theo và độ chênh lệch giá tiền của K mặt hàng là thấp nhất.
8. Một dây chuyền sản xuất có N (N<=100) vị trí. Có N công nhân, cho biết năng suất của
công nhân thứ i mà làm ở vị trí thứ j là Cij (Cij : Integer). Hãy sắp xếp N công nhân vào N
vị trí sao cho đạt năng suất cao nhất.
9. Cho ma trận vuông cấp 8 chứa các số nguyên. Tìm giá trị lớn nhất của tổng 8 số hạng
trên ma trận số trên sao cho 2 số hạng bất kỳ trong 8 số hạng trên không nằm trên cùng
một hàng, không cùng nằm trên một cột và không cùng nằm trên đường chéo .
10. Cho một bảng A có M hàng, N cột (3 ≤ M, N ≤ 50), Mỗi phần tử của bảng là một số nguyên
nhận giá trị từ 0 đến 99. Cho một số K (2 ≤ K ≤ Min(M, N)). Tìm K phần tử trong bảng A để
tổng của K phần tử này là lớn nhất, với điều kiện là trên mỗi hàng chọn nhiều nhất một
phần tử, mỗi cột chọn nhiều nhất một phần tử.
11. Một cơ sở sản xuất cần phân công M nhân viên tham gia thực hiện N hợp đồng sản xuất
sản phẩm (M >= N). Mỗi nhân viên chỉ tham gia thực hiện một hợp đồng. Người ta dự
tính rằng, nếu phân công i nhân viên tham gia thực hiện hợp đồng j thì có thời gian hoàn
thành hợp đồng là T[i,j]. Hãy tìm phương án phân công mỗi hợp đồng bao nhiêu nhân
viên sao cho tổng số thời gian hoàn thành N hợp đồng là ít nhất.

52 Mã hóa

You might also like