1. 1
Bài toán đổi tiền xu
Phát biểu: Giả sử có các mệnh giá tiền xu là x1, x2, …, xk. Tìm số lượng đồng tiền
xu nhỏ nhất để có thể đổi n xu.
Cho rằng, đồng xu có mệnh giá nhỏ nhất là 1 xu để đảm bảo luôn có lời giải.
Giải thuật
moneyChange(coins[1..k], money) {
minCoins = money;
for (i = 1; i k; i++)
if (coins[i] == money)
return 1;
for (i = 1; i money / 2; i++) {
tmpSum = moneyChange(coins, i) + moneyChange(coins, money - i);
if (tmpSum < minCoins)
minCoins = tmpSum;
}
return minCoins;
}
2. 2
Giảm để trị
Tính an
Chia để trị:
Giảm để trị:
Bài toán đổi tiền xu
Giải thuật
moneyChange(coins[1..k], money) {
minCoins = money;
for (i = 1; i k; i++)
if (coins[i] == money)
return 1;
for (i = 1; i k; i++)
if (money > coins[i]) {
tmpSum = 1 + moneyChange(coins, money - coins[i]);
if (tmpSum < minCoins)
minCoins = tmpSum;
}
return minCoins;
}
3. 3
Vấn đề chọn
Phát biểu: Tìm phần tử nhỏ thứ k trong dãy S = {s1, s2, …, sn}, với k [1, n].
Chọn (ngẫu nhiên) phần tử pivot thuộc dãy S và tách S thành 3 dãy con:
– Sleft: chứa các phần tử nhỏ hơn pivot.
– Spivot: chứa các phần tử bằng pivot.
– Sright: chứa các phần tử lớn hơn pivot.
với chi phí tuyến tính.
Giải thuật xử lý như sau:
– Nếu k |Sleft|: Tìm kiếm phần tử nhỏ thứ k trong dãy Sleft.
– Nếu |Sleft| < k |Sleft| + |Spivot|: pivot chính là giá trị nhỏ thứ k cần tìm.
– Nếu |Sleft| + |Spivot| < k: Tìm kiếm phần tử nhỏ thứ k – (|Sleft| + |Spivot|) trong dãy Sright.
Cài đặt không sử dụng mảng phụ
Sau một phép phân hoạch với pivot là phần tử chốt, ta có được pos là vị trí của
pivot trong S. Nhận thấy:
– Nếu pos = k: pivot chính là phần tử nhỏ thứ k trong dãy.
– Nếu pos > k: phần tử nhỏ thứ k thuộc về Sleft = {s1, …, spos–1}.
– Nếu pos < k: phần tử nhỏ thứ k thuộc về Sright = {spos+1 , …, sn}.
Giải thuật
Selection(S[1..n], lower, upper, k) {
index = random(lower, upper);
pos = Partition(S, lower, upper, index); // S[pos] = pivot
if (pos == k)
return S[pos];
if (pos > k)
Selection(S, lower, pos – 1, k);
if (pos < k)
Selection(S, pos + 1, upper, k);
}
Partition(S, lower, upper, pos) {
pivot = S[pos];
S[lower] S[pos];
pos = lower;
for (i = lower + 1; i upper; i++)
if (pivot > S[i]) {
pos++;
S[i] S[pos];
}
S[lower] S[pos];
return pos;
}