1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Đề Cương Ôn Tập Phân Tích Thiết Kế Thuật Toán

39 9 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Đề Cương Ôn Tập Phân Tích Thiết Kế Thuật Toán
Chuyên ngành Phân tích thiết kế thuật toán
Thể loại Đề cương ôn tập
Định dạng
Số trang 39
Dung lượng 3,45 MB

Cấu trúc

  • 1. Cái ba lô (5)
  • 2. Lập lịch (7)
  • 3. Sắp xếp môn học (8)
  • 4. Đóng thùng (9)
  • 5. Rút tiền (11)
  • 6. Trồng hoa (13)
  • 1. Đếm hậu (15)
  • 2. Dãy nhị phân (17)
  • 3. Hoán vị (18)
  • 4. Mã đi tuần (19)
  • 5. Mã đi tuần theo chu trình đóng (20)
  • 6. Tổng các tập con (21)
  • 7. Sudoku (22)
  • 8. Tổ hợp chập k của n (23)
  • 1. Tính tổ hợp (24)
  • 2. Dãy Fibonacci (25)
  • 3. Tổng tập con (25)
  • 4. Cái ba lô (27)
  • 5. Dãy con tăng dài nhất (28)
  • 6. Đổi tiền (30)
  • 7. Độ dài xâu con dài nhất (31)
  • 1. Tìm kiếm nhị phân (32)
  • 2. Dãy con liên tục có tổng lớn nhất (34)
  • 3. Fibonacci (35)
  • 4. Tìm phần tử lớn nhất (36)
  • 5. Ước chung lớn nhất (36)
  • 6. Tính lũy thừa (37)
  • 7. Sắp xếp chèn (37)
  • 8. Sắp xếp trộn (39)

Nội dung

Đề cương chủ yếu về 4 thuật toán: Tham Lam, Chia Để Trị, Quay Lui và Quy Hoạch Động. Ngoài lý thuyết đơn giản ra, đề cương có 31 bài tập, không có đề bài, chỉ bao gồm ý tưởng giải, ví dụ đơn giản và code lập trình bằng C++ đầy đủ.

Sắp xếp môn học

Đoạn code trên giải quyết bài toán lựa chọn các khóa học sao cho số lượng khóa học được chọn là lớn nhất, mà không có hai khóa học nào trùng thời gian Ý tưởng chính của phương pháp Greedy trong đoạn code này là sắp xếp các khóa học theo thời gian kết thúc tăng dần, sau đó lựa chọn lần lượt các khóa học không trùng thời gian với nhau

Giả sử có 5 khóa học như sau:

Khóa học 1 (id=1): bắt đầu lúc 6, kết thúc lúc 7

Khóa học 2 (id=2): bắt đầu lúc 7, kết thúc lúc 9

Khóa học 3 (id=3): bắt đầu lúc 8, kết thúc lúc 14

Khóa học 4 (id=4): bắt đầu lúc 10, kết thúc lúc 20

Khóa học 5 (id=5): bắt đầu lúc 9, kết thúc lúc 12

Sử dụng phương pháp Greedy, ta sẽ sắp xếp các khóa học theo thời gian kết thúc tăng dần

Sau khi sắp xếp, ta lựa chọn lần lượt các khóa học không trùng thời gian với nhau Trong ví dụ này, ta sẽ lựa chọn các khóa học sau: 1, 2, 5, 4 Do đó, số lượng khóa học được chọn là 4 và đây là lịch trình tối ưu.

Đóng thùng

Ý tưởng chính của thuật toán là sắp xếp các đồ vật theo thứ tự giảm dần của kích thước, sau đó lần lượt đặt từng đồ vật vào thùng có thể chứa được nó Nếu không thể đặt vào thùng hiện tại, thì tìm thùng trống khác có thể chứa được và đặt đồ vật vào đó

Giả sử có các đồ vật có kích thước là {3, 2, 5, 1, 4, 3} và kích thước của thùng là 6 Chương trình sẽ thực hiện như sau:

Lần lượt đặt các đồ vật vào thùng:

Thùng 1: {5}, còn lại kích thước 1

Thùng 2: {4, 1}, còn lại kích thước 1

Thùng 3: {3, 3}, còn lại kích thước 0

Thùng 4: {2}, còn lại kích thước 4

Rút tiền

Sắp xếp các mệnh giá tiền giảm dần: Trước tiên, danh sách các mệnh giá tiền được sắp xếp theo thứ tự giảm dần, từ mệnh giá lớn nhất đến nhỏ nhất Điều này giúp chương trình rút tiền bằng các tờ tiền có mệnh giá lớn trước, giảm thiểu số lượng tờ tiền cần rút

Rút tiền từ mệnh giá lớn nhất đến nhỏ nhất: Thuật toán lặp qua từng mệnh giá tiền từ lớn nhất đến nhỏ nhất Với mỗi mệnh giá, nó tính số tờ tiền cần rút bằng cách chia số tiền cần rút cho mệnh giá đó và lấy phần nguyên của kết quả Sau đó, cập nhật số tiền cần rút cho lần lặp tiếp theo

Giả sử danh sách các mệnh giá tiền có sẵn là {100,000, 50,000, 40,000, 20,000, 10,000}, và người dùng muốn rút 180,000 VND từ máy ATM

Bắt đầu với mệnh giá 100,000 VND:

Số tờ tiền cần rút = 180,000 / 100,000 = 1 (phần nguyên)

Cập nhật số tiền cần rút: 180,000 - 1 * 100,000 = 80,000 VND

Tiếp tục với mệnh giá 50,000 VND:

Số tờ tiền cần rút = 80,000 / 50,000 = 1 (phần nguyên)

Cập nhật số tiền cần rút: 80,000 - 1 * 50,000 = 30,000 VND ….

Trồng hoa

Đếm hậu

- Sử dụng phương pháp quay lui để thử tất cả các vị trí có thể đặt quân hậu trên bàn cờ

- Sử dụng một mảng 1 chiều để lưu vị trí của các quân hậu trên các hàng của bàn cờ

 Bước 1: Tạo một hàm đệ quy XepHau(int i) để thử vị trí đặt quân hậu thứ i trên bàn cờ

 Bước 2: Trong hàm XepHau(int i), thử tất cả các cột trên hàng i để xem vị trí nào phù hợp để đặt quân hậu

 Bước 3: Kiểm tra xem vị trí đó có phù hợp để đặt quân hậu không bằng cách kiểm tra các quân hậu đã đặt trước đó Nếu vị trí đó hợp lệ, tiến hành đặt quân hậu và gọi đệ quy để thử vị trí tiếp theo

 Bước 4: Nếu đã đặt quân hậu vào vị trí cuối cùng trên bàn cờ (i == n), thì in ra cách xếp hậu đó

 Bước 5: Lặp lại các bước trên cho tất cả các quân hậu cho đến khi tìm được tất cả các cách xếp hậu đúng trên bàn cờ hoặc không còn cách nào thỏa mãn.

Dãy nhị phân

Thuật toán quay lui được sử dụng để sinh ra tất cả các tổ hợp nhị phân có độ dài n Ý tưởng chính của thuật toán là sử dụng một mảng để lưu trữ các giá trị 0 và 1, mỗi giá trị tại một vị trí của mảng biểu diễn cho một bit trong tổ hợp nhị phân Thuật toán sẽ thử tất cả các kết hợp có thể của các bit này, từ bit đầu tiên đến bit cuối cùng, và đệ quy tiến hành thử các giá trị có thể của bit tiếp theo cho đến khi đạt tới bit cuối cùng Khi đạt đến bit cuối cùng, thuật toán sẽ in ra kết quả và quay lui để thử các giá trị khác cho các bit trước đó

Dưới đây là các bước cụ thể của thuật toán:

- Khởi tạo một mảng có độ dài n để lưu trữ các giá trị của tổ hợp nhị phân

- Gọi hàm quay lui với các tham số là mảng đã khởi tạo, chỉ số của bit hiện tại (bắt đầu từ 1), và độ dài của tổ hợp nhị phân

- Lặp qua các giá trị có thể của bit hiện tại (0 hoặc 1)

- Gán giá trị cho bit hiện tại

- Nếu đã đạt tới bit cuối cùng, in ra tổ hợp nhị phân và kết thúc

- Nếu chưa đạt tới bit cuối cùng, gọi đệ quy để thử các giá trị cho bit tiếp theo

- Khi đã thử hết tất cả các giá trị cho bit hiện tại, quay lui để thử các giá trị khác cho bit trước đó.

Hoán vị

- Sử dụng một mảng x[] để lưu trữ hoán vị hiện tại và một mảng b[] để đánh dấu các số đã được chọn

- Sử dụng đệ quy để thử tất cả các cách chọn số cho vị trí hiện tại trong hoán vị

- Khi đã điền đủ n số vào x[], in ra hoán vị đó

Các bước giải: a Khởi tạo mảng x[] và b[] với giá trị ban đầu b Tạo hàm output() để in ra một hoán vị c Tạo hàm đệ quy hoanvi() để sinh ra tất cả các hoán vị:

- Với mỗi vị trí i từ 1 đến n, thử tất cả các số chưa được chọn để điền vào vị trí i

- Đánh dấu số đã chọn và gọi đệ quy để điền số tiếp theo

- Khi đã điền đủ n số, in ra hoán vị đó

- Hủy đánh dấu số đã chọn để thử các số khác d Gọi hàm hoanvi() từ main() để bắt đầu sinh và in ra tất cả các hoán vị của các số từ 1 đến n.

Mã đi tuần theo chu trình đóng

- Sử dụng một ma trận A[][] để lưu vị trí các bước di chuyển trên bàn cờ

- Sử dụng hai mảng X[] và Y[] để định nghĩa các hướng di chuyển từ mỗi ô

- Sử dụng biến dem để đếm số bước đã đi

- Sử dụng biến x_first và y_first để lưu vị trí ban đầu

- Sử dụng hàm xuat() để in ra bàn cờ sau mỗi bước di chuyển

- Sử dụng hàm diChuyen() để thực hiện việc di chuyển từ vị trí hiện tại đến các vị trí khác trên bàn cờ, đồng thời kiểm tra xem mã đã đi hết các ô chưa và đã trở về vị trí ban đầu chưa.

Sudoku

- Kiểm tra tính hợp lệ của giá trị trong ô: kiểm tra xem có thể đặt giá trị k vào vị trí (x, y) trên bảng Sudoku hay không Kiểm tra xem giá trị k đã tồn tại trong hàng, cột hoặc ô 3x3 chứa vị trí (x, y) chưa Nếu không hợp lệ, trả về 0; ngược lại trả về 1

- Giải bài toán Sudoku bằng đệ quy: Sử dụng phương pháp đệ quy để thử tất cả các giá trị từ 1 đến 9 cho ô hiện tại và tiếp tục đệ quy để thử giá trị tiếp theo cho ô kế tiếp Nếu không tìm thấy giải pháp, quay lui và thử các giá trị khác cho ô hiện tại

- Tìm kiếm giải pháp: kết thúc cột hiện tại, kiểm tra xem đã đến cuối bảng chưa Nếu đã đến cuối bảng, in ra giải pháp và kết thúc chương trình Nếu chưa, sẽ tiếp tục đệ quy với hàng tiếp theo Nếu ô hiện tại đã có giá trị, nó sẽ tiếp tục đệ quy với ô kế tiếp Nếu ô hiện tại chưa có giá trị, nó sẽ thử tất cả các giá trị hợp lệ cho ô đó.

Tổ hợp chập k của n

Tính tổ hợp

Ý tưởng chính là sử dụng một bảng hoặc một mảng để lưu trữ kết quả của các bài toán con nhỏ

 Ta bắt đầu với các trường hợp cơ bản: C(n, 0) = C(n, n) = 1

 Sau đó, ta sử dụng công thức tổ hợp: C(n, k) = C(n-1, k-1) + C(n-1, k) để tính toán các giá trị còn lại

 Bằng cách tính toán từ trên xuống dưới và từ trái sang phải, ta có thể xây dựng bảng hoặc mảng chứa kết quả của tất cả các bài toán con nhỏ

 Kết quả cuối cùng sẽ nằm ở ô góc phải dưới cùng của bảng hoặc mảng.

Dãy Fibonacci

Khởi tạo mảng F và giá trị ban đầu của dãy Fibonacci: Mảng F được khai báo với kích thước n và được sử dụng để lưu trữ các số trong dãy Fibonacci Ban đầu, hai phần tử đầu tiên của dãy Fibonacci là 0 và 1 được gán trực tiếp vào F[0] và F[1]

Duyệt qua từng phần tử của dãy Fibonacci từ 2 đến n: Sử dụng một vòng lặp, với mỗi giá trị i từ 2 đến n, tính giá trị của F[i] bằng cách cộng hai giá trị trước đó của dãy Fibonacci, tức là F[i-1] và F[i-2]

In ra dãy Fibonacci: Cuối cùng, dãy Fibonacci được in ra màn hình từ F[0] đến F[n].

Tổng tập con

Sử dụng bảng hoặc mảng: Bước đầu tiên là tạo một bảng hoặc mảng 1 chiều để lưu trữ kết quả của các bài toán con nhỏ Mỗi phần tử trong mảng này thường là một giá trị boolean, chỉ ra xem có thể tạo thành tổng mục tiêu từ một tập con của dãy ban đầu hay không

Trường hợp cơ bản: Khởi tạo các giá trị cơ bản của bảng hoặc mảng Ví dụ, nếu mục tiêu là 0, thì tất cả các giá trị trong mảng này đều là True vì có thể tạo ra tổng 0 từ bất kỳ tập con nào (bằng cách không chọn phần tử nào)

Tính toán các giá trị còn lại: Sử dụng phương pháp quy hoạch động, tính toán các giá trị còn lại của bảng hoặc mảng dựa trên giá trị của các bài toán con nhỏ hơn Mỗi ô của bảng hoặc mảng thường được tính toán dựa trên hai trường hợp: (a) nếu không bao gồm phần tử hiện tại, (b) nếu bao gồm phần tử hiện tại

Trả về kết quả: Kết quả cuối cùng thường được lấy từ ô cuối cùng của bảng hoặc mảng Nếu giá trị tại ô này là True, có nghĩa là có thể tạo thành tổng mục tiêu từ một tập con của dãy ban đầu.

Cái ba lô

Xây dựng bảng: Tạo một bảng 2 chiều có kích thước n x W, trong đó n là số lượng đồ vật và W là trọng lượng tối đa của cái ba lô

Khởi tạo giá trị ban đầu: Đặt tất cả các giá trị trong hàng đầu tiên và cột đầu tiên của bảng là 0

Tính toán giá trị tối ưu: Sử dụng công thức tối ưu L[i][t] = max(L[i - 1][t], L[i][t-g[i]] + v[i]), trong đó v [i] là giá trị của đồ vật thứ i, g[i] là trọng lượng của đồ vật thứ i, và L[i][t] là giá trị tối ưu có thể đạt được với i đồ vật và trọng lượng t

Trả về giá trị tối ưu: Giá trị tối ưu cuối cùng sẽ nằm ở ô góc dưới cùng bên phải của bảng

Dãy con tăng dài nhất

Khởi tạo mảng L để lưu độ dài của dãy con tăng dài nhất kết thúc tại mỗi vị trí của dãy

Bổ sung phần tử ảo INT_MAX vào cuối dãy A

Duyệt qua từng phần tử của dãy, cập nhật giá trị của L[i] bằng cách so sánh với các phần tử trước đó

Trả về độ dài của dãy con tăng dài nhất và in ra dãy con đó

Đổi tiền

Khởi tạo mảng P và L: Mảng P được khởi tạo với giá trị INT_MAX, đại diện cho số lượng đồng tiền ít nhất cần để đổi đến số tiền tương ứng Mảng L cũng được khởi tạo tương tự nhưng có thêm phần tử 0 ở đầu

Duyệt qua từng loại đồng tiền và mỗi mức số tiền từ 1 đến M: Tại mỗi bước lặp, ta cập nhật mảng L dựa trên mảng P, sử dụng các loại đồng tiền hiện có

Cập nhật mảng L: Tại mỗi mức số tiền t, ta cập nhật L[t] bằng giá trị nhỏ nhất giữa P[t] (số lượng đồng tiền ít nhất cho số tiền t mà không sử dụng đồng tiền hiện tại) và L[t-a[i]] + 1 (số lượng đồng tiền ít nhất cho số tiền t - a[i] cộng thêm một đồng tiền hiện tại)

Trả về kết quả: Trả về giá trị cuối cùng của L[M], tức là số lượng đồng tiền ít nhất cần thiết để đổi số tiền M

Độ dài xâu con dài nhất

 Mảng P được khởi tạo với giá trị 0 cho tất cả các phần tử, đại diện cho xâu con chung dài nhất tính đến thời điểm trước đó

 Mảng L được khởi tạo với giá trị 0 cho phần tử đầu tiên, đại diện cho xâu con chung dài nhất tính đến thời điểm hiện tại

Duyệt qua từng ký tự trong xâu X và Y:

 Nếu X[i] bằng Y[j], tức là ta tìm thấy một ký tự mới trong xâu con chung Ta cập nhật giá trị của L[j] bằng giá trị của P[j-1]

 Ngược lại, ta cập nhật giá trị của L[j] bằng giá trị lớn nhất giữa P[j] và L[j-1]

Sau khi duyệt qua tất cả các ký tự trong X và Y, ta cập nhật mảng P bằng mảng L và tiếp tục duyệt

Kết quả cuối cùng là giá trị của L[ny], tức là độ dài của xâu con chung dài nhất

Tìm kiếm nhị phân

1 Chia mảng thành các phần nhỏ: Đầu tiên, chúng ta chia mảng thành hai phần bằng cách chọn phần tử ở giữa mảng làm điểm chia Phần này được chia thành hai phần nhỏ hơn, phần bên trái và phần bên phải

2 Kiểm tra phần tử ở giữa:

So sánh phần tử ở giữa mảng với giá trị cần tìm Nếu phần tử này trùng khớp với giá trị cần tìm, chúng ta đã tìm thấy nó và trả về chỉ số của phần tử đó

3 Chọn phần mảng để tiếp tục tìm kiếm:

Nếu phần tử ở giữa mảng lớn hơn giá trị cần tìm, chúng ta chỉ cần tìm kiếm trong nửa mảng bên trái

Nếu phần tử ở giữa mảng nhỏ hơn giá trị cần tìm, chúng ta chỉ cần tìm kiếm trong nửa mảng bên phải

4 Lặp lại quá trình cho đến khi tìm thấy hoặc không thể tìm thấy:

Lặp lại quá trình trên cho đến khi tìm thấy phần tử cần tìm hoặc phần tử này không tồn tại trong mảng Nếu phần tử không tồn tại, chúng ta sẽ trả về một giá trị đặc biệt để biểu thị việc không tìm thấy

Nếu tìm thấy phần tử, trả về chỉ số của nó trong mảng

Nếu không tìm thấy, trả về một giá trị đặc biệt để biểu thị việc không tìm thấy.

Dãy con liên tục có tổng lớn nhất

1 Khởi tạo các biến: max_so_far: lưu trữ tổng lớn nhất của dãy con liên tục đã tìm thấy curr_max: lưu trữ tổng tạm thời của dãy con liên tục hiện tại begin và end: lưu trữ chỉ số của dãy con liên tục có tổng lớn nhất

Bắt đầu từ phần tử thứ 2 của mảng, vì chúng ta đã xử lý phần tử đầu tiên ở bước khởi tạo Duyệt qua từng phần tử của mảng:

So sánh a[i] với curr_max + a[i] Nếu a[i] lớn hơn tổng tạm thời hiện tại (curr_max + a[i]), tức là bắt đầu một dãy con mới từ a[i]

Cập nhật curr_max thành giá trị lớn hơn giữa a[i] và curr_max + a[i]

So sánh max_so_far với curr_max để cập nhật giá trị max_so_far nếu cần

3 Xác định dãy con liên tục có tổng lớn nhất:

Sau khi duyệt qua toàn bộ mảng, max_so_far sẽ chứa tổng lớn nhất của dãy con liên tục

Sử dụng begin và end để in ra dãy con liên tục có tổng lớn nhất

Trả về giá trị max_so_far, tức là tổng lớn nhất của dãy con liên tục.

Fibonacci

Sử dụng một hàm đệ quy để tính số Fibonacci của số nguyên dương n

Nếu n nhỏ hơn 2, trả về n vì các số Fibonacci đầu tiên là 0 và 1

Nếu không, tính số Fibonacci của n-1 và n-2 bằng cách đệ quy, sau đó cộng chúng lại với nhau.

Tìm phần tử lớn nhất

Tìm phần tử lớn nhất trong mảng A[] từ chỉ số low đến high với low = 0 và high = n-1

Nếu low và high trùng nhau (tức là chỉ có một phần tử trong mảng), trả về phần tử đó là phần tử lớn nhất

Ngược lại, chia mảng thành hai phần bằng cách tính chỉ số trung bình mid

Gọi đệ quy hàm FindMax trên hai phần tử mảng con bên trái và bên phải của mid, sau đó so sánh hai giá trị trả về

Trả về phần tử lớn nhất của hai phần tử mảng con đó.

Ước chung lớn nhất

Sử dụng thuật toán Euclid, trong đó gcd(a, b) là ước số chung lớn nhất của hai số a và b Trong khi b khác 0:

Gán giá trị của b cho a và giá trị của r cho b

Trả về giá trị của a, đó là ước số chung lớn nhất của a và b.

Tính lũy thừa

Sử dụng phương pháp chia để trị để tính lũy thừa của một số a với một số mũ n

Ngược lại, tính lũy thừa của a^(n/2) bằng cách đệ quy gọi hàm power(a, n/2)

Nếu n là số chẵn, trả về x * x, nếu n là số lẻ, trả về x * x * a.

Sắp xếp chèn

Bước 1: Bắt đầu từ phần tử thứ hai của mảng (index 1), lấy phần tử hiện tại và gán vào biến v

Bước 2: Lặp qua các phần tử trước đó (các phần tử đã được sắp xếp) để tìm vị trí đúng cho phần tử v

Bước 3: So sánh phần tử đang xét (v) với các phần tử đứng trước trong mảng Nếu phần tử trước đó lớn hơn v, di chuyển phần tử đó sang phải để tạo ra một vị trí trống cho v

Bước 4: Lặp lại bước 3 cho đến khi tìm được vị trí thích hợp cho v

Bước 5: Gán v vào vị trí thích hợp trong mảng

Bước 6: Lặp lại các bước trên cho các phần tử tiếp theo trong mảng Điều này tiếp tục cho đến khi tất cả các phần tử được sắp xếp.

Ngày đăng: 13/05/2024, 20:51

w