Tuyển dụng
Viettel IDC

Dynamic programming là gì? Tìm hiểu về thuật toán quy hoạch động (DP)

02/07/2026

Nhiều bài toán đệ quy trở nên chậm vì liên tục tính lại cùng một kết quả. Thuật toán quy hoạch động khắc phục hạn chế này bằng cách lưu các trạng thái đã xử lý để tái sử dụng, qua đó rút ngắn thời gian thực thi. Cùng Viettel IDC tìm hiểu Dynamic Programming là gì, cách hoạt động và cách áp dụng qua ví dụ cụ thể.

Dynamic programming là gì?

Dynamic Programming (Quy hoạch động) là một phương pháp giải quyết các bài toán phức tạp bằng cách chia chúng thành các bài toán con nhỏ hơn, giải quyết các bài toán con đó một lần duy nhất và lưu trữ kết quả để tránh tính toán lại nhiều lần. Cách tiếp cận này giúp hạn chế các phép tính lặp lại, từ đó cải thiện đáng kể thời gian xử lý so với đệ quy thông thường.

Dynamic programming là gì?

Cơ chế hoạt động của quy hoạch động

Quy hoạch động hoạt động bằng cách xác định các bài toán con bị lặp lại trong quá trình giải, tính kết quả của từng bài toán con một lần rồi lưu lại để tái sử dụng. Khi cần xử lý một trạng thái đã xuất hiện, thuật toán lấy trực tiếp kết quả đã lưu thay vì thực hiện lại toàn bộ phép tính.

Dynamic programming thường trải qua các bước cơ bản sau:

- Chia nhỏ bài toán: Phân tích bài toán lớn thành các bài toán con nhỏ hơn có cùng bản chất.

- Xây dựng công thức truy hồi: Thiết lập mối liên hệ toán học giữa bài toán lớn và các bài toán con (ví dụ: F(n) = F(n-1) + F(n-2)).

- Lưu trữ kết quả (Memoization/Tabulation): Tạo một bảng (mảng) để lưu lại kết quả của các bài toán con đã giải.

- Giải từ dưới lên (hoặc từ trên xuống): Giải quyết các bài toán nhỏ nhất (trường hợp cơ sở), lưu kết quả, sau đó dùng chúng để giải các bài toán lớn hơn.

Các thuộc tính của quy hoạch động

Không phải bài toán nào cũng phù hợp để giải bằng thuật toán Dynamic Programming. Phương pháp này phát huy hiệu quả khi bài toán có thể chia thành các bài toán con liên quan và kết quả của chúng được tái sử dụng trong quá trình tính toán.

Cấu trúc con tối ưu

Cấu trúc con tối ưu là thuộc tính cho thấy lời giải tốt nhất của bài toán lớn có thể được xây dựng từ lời giải tốt nhất của các bài toán con. Nói cách khác, nếu một phần trong lời giải tổng thể chưa tối ưu thì kết quả cuối cùng cũng khó đạt mức tối ưu.

Ví dụ, cần tìm đường đi ngắn nhất từ A đến C và bắt buộc đi qua B. Khi đó, đường đi tối ưu từ A đến C sẽ được tạo từ đường đi ngắn nhất từ A đến B kết hợp với đường đi ngắn nhất từ B đến C. Nếu một trong hai đoạn đường này chưa phải ngắn nhất, toàn bộ hành trình cũng không thể là phương án tối ưu.

Các bài toán con chồng lặp

Các bài toán con chồng lặp xuất hiện khi cùng một bài toán nhỏ được giải nhiều lần trong quá trình xử lý bài toán lớn. Thay vì tính lại từ đầu, quy hoạch động lưu kết quả của mỗi bài toán con và sử dụng lại khi gặp trạng thái tương tự.

Ví dụ, khi tính F(5) theo dãy Fibonacci, thuật toán cần tính F(4) và F(3). Trong quá trình tính F(4), giá trị F(3) tiếp tục xuất hiện, còn F(2) có thể được sử dụng nhiều lần ở các nhánh khác nhau. Quy hoạch động lưu sẵn các giá trị F(2), F(3) và F(4), nhờ đó tránh thực hiện lại cùng một phép tính.

Các thuộc tính của quy hoạch động

Ưu điểm và nhược điểm của Dynamic programming là gì

Dynamic Programming giúp tối ưu các bài toán có nhiều trạng thái lặp lại và cấu trúc con tối ưu. Tuy nhiên, phương pháp này cũng đòi hỏi cách xây dựng trạng thái hợp lý và có thể tiêu tốn nhiều bộ nhớ.

Ưu điểm của Dynamic Programming

- Giảm phép tính lặp bằng cách lưu và tái sử dụng kết quả của các bài toán con.

- Cải thiện đáng kể thời gian thực thi so với đệ quy thông thường trong nhiều trường hợp.

- Phù hợp với các bài toán tối ưu như tìm đường đi ngắn nhất, ba lô, chuỗi con chung dài nhất hoặc phân bổ tài nguyên.

- Có thể triển khai linh hoạt theo hướng từ trên xuống bằng memoization hoặc từ dưới lên bằng tabulation.

- Đảm bảo tìm được lời giải tối ưu khi bài toán đáp ứng đúng các điều kiện của quy hoạch động.

Nhược điểm của Dynamic Programming

- Tiêu tốn thêm bộ nhớ để lưu trạng thái và kết quả trung gian.

- Khó xác định trạng thái, công thức truy hồi và trường hợp cơ sở đối với bài toán phức tạp.

- Mã nguồn có thể khó đọc và khó bảo trì nếu số lượng trạng thái quá lớn.

- Không phù hợp với bài toán không có cấu trúc con tối ưu hoặc bài toán con chồng lặp.

- Hiệu suất có thể giảm khi không gian trạng thái quá rộng hoặc lưu nhiều kết quả không cần thiết.

Phân biệt Memoization và Tabulation trong Dynamic Programming

Memoization và Tabulation đều là hai cách triển khai phổ biến của Dynamic Programming. Điểm chung của chúng là lưu lại kết quả của các bài toán con để tránh tính toán lặp lại, nhưng khác nhau về thứ tự xử lý và cách tổ chức thuật toán.

Tiêu chí

Memoization

Tabulation

Hướng tiếp cận

Từ trên xuống, bắt đầu từ bài toán lớn.

Từ dưới lên, bắt đầu từ các trường hợp cơ sở.

Cách triển khai

Kết hợp đệ quy với bộ nhớ đệm.

Sử dụng vòng lặp và bảng lưu trạng thái.

Trạng thái được tính

Chỉ tính những trạng thái thực sự cần thiết.

Thường tính lần lượt toàn bộ trạng thái đến kết quả cần tìm.

Cấu trúc lưu trữ

Mảng, dictionary, hash map hoặc cache.

Chủ yếu sử dụng mảng hoặc bảng dp.

Bộ nhớ ngăn xếp

Có sử dụng call stack do dùng đệ quy.

Không phụ thuộc vào call stack.

Rủi ro

Có thể gặp lỗi tràn ngăn xếp khi độ sâu đệ quy quá lớn.

Ít gặp lỗi tràn ngăn xếp hơn.

Khả năng xây dựng

Thường dễ triển khai khi đã có công thức đệ quy.

Cần xác định đúng thứ tự tính các trạng thái.

Hiệu suất

Có thể phát sinh chi phí do lời gọi hàm đệ quy.

Thường có tốc độ ổn định hơn nhờ sử dụng vòng lặp.

Memoization là gì?

Memoization là cách triển khai quy hoạch động theo hướng từ trên xuống. Thuật toán bắt đầu từ bài toán cần giải, sau đó tiếp tục gọi đệ quy để xử lý các bài toán con.

Khi một trạng thái được tính lần đầu, kết quả sẽ được lưu vào bộ nhớ đệm. Nếu trạng thái đó xuất hiện lại, thuật toán lấy trực tiếp kết quả đã lưu thay vì tính lại.

Ví dụ tính số cách leo cầu thang bằng Memoization:

def count_ways(n, memo=None):

    if memo is None:

        memo = {}

 

    if n < 0:

        return 0

 

    if n <= 1:

        return 1

 

    if n in memo:

        return memo[n]

 

    memo[n] = count_ways(n - 1, memo) + count_ways(n - 2, memo)

    return memo[n]

 

Trong đoạn mã trên, dictionary memo lưu số cách leo đến từng bậc. Mỗi trạng thái chỉ được tính khi cần và được tái sử dụng trong các lần gọi tiếp theo.

Tabulation là gì?

Tabulation là cách triển khai quy hoạch động theo hướng từ dưới lên. Thuật toán bắt đầu từ các trường hợp cơ sở, sau đó sử dụng kết quả đã có để lần lượt tính các trạng thái lớn hơn. Phương pháp này thường sử dụng vòng lặp thay cho đệ quy, nhờ đó hạn chế chi phí gọi hàm và tránh nguy cơ tràn ngăn xếp.

Ví dụ tính số cách leo cầu thang bằng Tabulation:

def count_ways(n):

    if n < 0:

        return 0

 

    if n <= 1:

        return 1

 

    dp = [0] * (n + 1)

    dp[0] = 1

    dp[1] = 1

 

    for i in range(2, n + 1):

        dp[i] = dp[i - 1] + dp[i - 2]

 

    return dp[n]

Trong trường hợp này, thuật toán tính lần lượt từ dp[0] đến dp[n]. Mỗi giá trị được xây dựng từ hai trạng thái đứng trước.

Tabulation là gì?

Trường hợp nào nên sử dụng Dynamic programming?

Dynamic Programming thường được lựa chọn khi bài toán có nhiều hướng xử lý nhưng các trạng thái trung gian lại lặp lại. Dựa vào những dấu hiệu dưới đây, bạn có thể xác định liệu quy hoạch động có phải là phương pháp phù hợp hay không.

Trường hợp

Dấu hiệu nhận biết

Ví dụ

Có cấu trúc con tối ưu

Lời giải của bài toán lớn được xây dựng từ lời giải tối ưu của các bài toán nhỏ hơn.

Tìm đường đi ngắn nhất, bài toán ba lô.

Có bài toán con chồng lặp

Cùng một bài toán con hoặc trạng thái xuất hiện nhiều lần trong quá trình xử lý.

Tính dãy Fibonacci, bài toán leo cầu thang.

Cần tìm phương án tối ưu

Bài toán yêu cầu tìm giá trị lớn nhất, nhỏ nhất hoặc phương án tốt nhất.

Tối đa hóa lợi nhuận, tối thiểu hóa chi phí.

Có thể biểu diễn bằng trạng thái

Mỗi giai đoạn của bài toán có thể mô tả bằng một hoặc nhiều biến trạng thái.

Số phần tử đã xét, vị trí hiện tại, trọng lượng còn lại.

Có công thức truy hồi rõ ràng

Kết quả của trạng thái hiện tại có thể tính từ các trạng thái trước đó.

F(n) = F(n-1) + F(n-2).

Đệ quy gây lặp phép tính

Cách giải đệ quy thông thường phải tính lại nhiều kết quả giống nhau.

Fibonacci, đổi tiền, chuỗi con chung dài nhất.

Ví dụ cụ thể về bài toán quy hoạch động

Một ví dụ phổ biến của quy hoạch động là bài toán đếm số cách leo cầu thang. Giả sử có một cầu thang gồm n bậc, mỗi lần người leo có thể bước 1 hoặc 2 bậc. Yêu cầu là tính tổng số cách khác nhau để đi từ mặt đất lên bậc thứ n.

Phân tích bài toán

Để đến bậc thứ n, người leo chỉ có thể đi từ bậc n - 1 bằng một bước hoặc từ bậc n - 2 bằng hai bước. Vì vậy, số cách đến bậc thứ n được tính theo công thức:

dp[n] = dp[n - 1] + dp[n - 2]

Trong đó, dp[n] là số cách leo đến bậc thứ n. Hai trường hợp cơ sở gồm:

- dp[0] = 1: Có một cách đứng tại vị trí ban đầu.

- dp[1] = 1: Chỉ có một cách bước lên bậc thứ nhất.

Tính số cách leo cầu thang với n = 5

Từ hai giá trị cơ sở, thuật toán tính lần lượt:

- dp[2] = dp[1] + dp[0] = 2

- dp[3] = dp[2] + dp[1] = 3

- dp[4] = dp[3] + dp[2] = 5

- dp[5] = dp[4] + dp[3] = 8

Như vậy, có 8 cách để leo lên cầu thang gồm 5 bậc:

- 1 + 1 + 1 + 1 + 1

- 1 + 1 + 1 + 2

- 1 + 1 + 2 + 1

- 1 + 2 + 1 + 1

- 2 + 1 + 1 + 1

- 1 + 2 + 2

- 2 + 1 + 2

- 2 + 2 + 1

Cách triển khai bằng quy hoạch động

Với phương pháp tabulation, thuật toán tính từ trạng thái nhỏ đến trạng thái lớn và lưu kết quả trong mảng:

def count_ways(n):

    if n <= 1:

        return 1

 

    dp = [0] * (n + 1)

    dp[0] = 1

    dp[1] = 1

 

    for i in range(2, n + 1):

        dp[i] = dp[i - 1] + dp[i - 2]

 

    return dp[n]

Bài toán này phù hợp với quy hoạch động vì có cấu trúc con tối ưu và các bài toán con chồng lặp. So với đệ quy thông thường có thể mất O(2^n), quy hoạch động giảm thời gian xử lý xuống còn O(n).

Kết luận

Qua những nội dung trên, Dynamic Programming là gì có thể được nhìn nhận như một phương pháp tối ưu thuật toán bằng cách lưu và tái sử dụng kết quả của các bài toán con. Cách tiếp cận này đặc biệt phù hợp với những bài toán có trạng thái lặp và cần tìm lời giải tối ưu trong thời gian ngắn hơn.

Để được hỗ trợ tư vấn và tìm hiểu các dịch vụ của Viettel, bạn có thể liên hệ trực tiếp tới Viettel IDC qua các kênh:

- Hotline: 1800 8088 (miễn phí cước gọi)

- Fanpage: https://www.facebook.com/viettelidc  

Bình luận ()

Đăng nhập | Đăng ký
để gửi bình luận
Ý kiến của bạn sẽ được xét duyệt trước khi đăng.
Ý kiến của bạn sẽ được xét duyệt trước khi đăng.
Ý kiến của bạn sẽ được xét duyệt trước khi đăng.
Xem thêm bình luận

Tin liên quan

06/10/2026

Có nên sử dụng Cloud miễn phí không? Ưu điểm và rủi ro cần lưu ý

Có nên sử dụng Cloud miễn phí không? Lợi ích, giới hạn tài nguyên, rủi ro dữ liệu và chi phí phát sinh trước khi lựa chọn cho nhu cầu của doanh nghiệp.

06/10/2026

Đánh giá các nhà cung cấp Cloud ở Việt Nam 2026: Top 10 uy tín nhất

Đánh giá các nhà cung cấp Cloud ở Việt Nam 2026, so sánh 10 đơn vị về hiệu năng, bảo mật, chi phí và hỗ trợ giúp doanh nghiệp lựa chọn dịch vụ Cloud phù hợp.

06/10/2026

Top 5 các nền tảng IoT cloud hàng đầu tại Việt Nam

Các nền tảng IoT cloud hàng đầu tại Việt Nam gồm Viettel IDC, VNPT, FPT, CMC và VNG, đáp ứng nhu cầu lưu trữ, xử lý dữ liệu và mở rộng hệ thống cho doanh nghiệp.

06/10/2026

Rủi ro khi doanh nghiệp sử dụng lậu các phần mềm: Cái giá của tiết kiệm

Rủi ro khi doanh nghiệp sử dụng lậu các phần mềm đe dọa tài chính, dữ liệu và uy tín thương hiệu, khiến khoản tiết kiệm ban đầu trở thành gánh nặng lâu dài.

06/10/2026

Mua phần mềm bản quyền ở đâu uy tín tại Việt Nam? Top 5 nhà cung cấp chất lượng

Mua phần mềm bản quyền ở đâu uy tín tại Việt Nam? Top 5 nhà cung cấp đáng tin cậy, giúp bạn chọn đúng địa chỉ và gói bản quyền phù hợp với nhu cầu.

06/10/2026

Các nền tảng làm việc số có bảo mật không? Rủi ro và cách phòng tránh

Các nền tảng làm việc số có bảo mật không? Cách dữ liệu được bảo vệ, những rủi ro cần lưu ý và giải pháp tăng cường an toàn cho doanh nghiệp.

05/10/2026

Làm sao kiểm tra chi phí gia hạn và độ tin cậy của nhà đăng ký tên miền?

Làm sao kiểm tra chi phí gia hạn và độ tin cậy của nhà đăng ký tên miền? Hướng dẫn xem bảng giá, xác minh uy tín để chọn dịch vụ phù hợp cho doanh nghiệp.

05/10/2026

Rủi ro khi mua lại tên miền: Những điều cần lưu ý khi mua tên miền cũ

Rủi ro khi mua lại tên miền có thể khiến doanh nghiệp mất quyền sử dụng, tốn chi phí xử lý tranh chấp và gặp khó khăn khi xây dựng website.

05/10/2026

10 tiêu chí lựa chọn nền tảng làm việc số cho doanh nghiệp

Tiêu chí lựa chọn nền tảng làm việc số cho doanh nghiệp gồm những gì? 10 yếu tố quan trọng nhất để đánh giá giải pháp phù hợp với nhu cầu và ngân sách.

05/10/2026

BitLocker là gì? Cách hoạt động, cách bật và những lưu ý quan trọng

BitLocker là gì và hoạt động như thế nào? Tìm hiểu vai trò của TPM, Recovery Password, các tùy chọn mã hóa và cách bật BitLocker trên Windows.