Sự khác biệt giữa phân chia và chinh phục Algo và lập trình động


140

Sự khác biệt giữa thuật toán phân chia và chinh phục và thuật toán lập trình động là gì? Hai thuật ngữ khác nhau như thế nào? Tôi không hiểu sự khác biệt giữa chúng.

Xin lấy một ví dụ đơn giản để giải thích bất kỳ sự khác biệt giữa hai và trên mặt đất mà chúng có vẻ giống nhau.

Câu trả lời:


156

Phân chia và chinh phục

Phân chia và chinh phục hoạt động bằng cách chia vấn đề thành các vấn đề phụ, chinh phục từng vấn đề phụ một cách đệ quy và kết hợp các giải pháp này.

Lập trình năng động

Lập trình động là một kỹ thuật để giải quyết các vấn đề với các bài toán con chồng chéo. Mỗi vấn đề phụ chỉ được giải quyết một lần và kết quả của mỗi vấn đề phụ được lưu trữ trong một bảng (thường được triển khai dưới dạng mảng hoặc bảng băm) cho các tham chiếu trong tương lai. Các giải pháp phụ này có thể được sử dụng để có được giải pháp ban đầu và kỹ thuật lưu trữ các giải pháp cho vấn đề phụ được gọi là ghi nhớ.

Bạn có thể nghĩ về DP = recursion + re-use

Một ví dụ kinh điển để hiểu sự khác biệt sẽ là xem cả hai cách tiếp cận này để đạt được số thứ n Dailymotion. Kiểm tra tài liệu này từ MIT.


Cách tiếp cận phân chia và chinh phục Cách tiếp cận phân chia và chinh phục

Phương pháp lập trình động nhập mô tả hình ảnh ở đây


9
Làm thế nào bạn thực hiện những hình ảnh? sử dụng chuột?
Vihaan Verma

34
Tôi nghĩ rằng dòng quan trọng nhất trong toàn bộ câu trả lời này là: "các bài toán con chồng chéo". DP có nó, Phân chia và chinh phục không
Hasan Iqbal

@HasanIqbalAnik Vấn đề phụ chồng chéo có nghĩa là một vấn đề xảy ra lặp đi lặp lại. Giống như giải fn-2 trong ví dụ hiển thị ở trên. Vì vậy, trong D & C nó đã có và đây là lý do tại sao nó không hiệu quả như DP.
Meena Chaudhary

1
Lạ thật! 'Các bài toán con chồng chéo' bạn đang nói về vấn đề nhưng 'lập trình động' là một loại thuật toán. Tôi nghĩ điều quan trọng là phải phân biệt 'vấn đề' và 'thuật toán'.
Chu

Có, DP ghi nhớ các phần chồng chéo để đạt được lợi thế so với Phân chia và Chinh phục.
imagineerThat

25

Sự khác biệt khác giữa phân chia và chinh phục và lập trình động có thể là:

Phân chia và chinh phục:

  1. Có nhiều công việc hơn cho các vấn đề phụ và do đó có nhiều thời gian hơn.
  2. Trong phân chia và chinh phục các vấn đề phụ là độc lập với nhau.

Lập trình năng động:

  1. Giải quyết các vấn đề phụ chỉ một lần và sau đó lưu trữ nó trong bảng.
  2. Trong lập trình động, bài toán con không độc lập.

Các thuật toán phân chia và chinh phục không nhất thiết phải thực hiện nhiều công việc hơn các giải pháp thay thế DP của chúng. Một ví dụ là thuật toán của Erickson để tìm tiến trình số học tối đa.
Michael Foukarakis

17

đôi khi khi lập trình đệ quy, bạn gọi hàm với cùng một tham số nhiều lần là không cần thiết.

Ví dụ về các số Fibonacci nổi tiếng:

           index: 1,2,3,4,5,6...
Fibonacci number: 1,1,2,3,5,8...

function F(n) {
    if (n < 3)
        return 1
    else
        return F(n-1) + F(n-2)
}

Hãy chạy F (5):

F(5) = F(4) + F(3)
     = {F(3)+F(2)} + {F(2)+F(1)}
     = {[F(2)+F(1)]+1} + {1+1}
     = 1+1+1+1+1

Vậy ta đã gọi: 1 lần F (4) 2 lần F (3) 3 lần F (2) 2 lần F (1)

Phương pháp lập trình động: nếu bạn gọi một hàm có cùng tham số nhiều lần, hãy lưu kết quả vào một biến để truy cập trực tiếp vào lần sau. Cách lặp lại:

if (n==1 || n==2)
    return 1
else
    f1=1, f2=1
    for i=3 to n
         f = f1 + f2
         f1 = f2
         f2 = f

Hãy gọi lại F (5):

fibo1 = 1
fibo2 = 1 
fibo3 = (fibo1 + fibo2) = 1 + 1 = 2
fibo4 = (fibo2 + fibo3) = 1 + 2 = 3
fibo5 = (fibo3 + fibo4) = 2 + 3 = 5

Như bạn có thể thấy, bất cứ khi nào bạn cần nhiều cuộc gọi, bạn chỉ cần truy cập vào biến tương ứng để nhận giá trị thay vì tính toán lại.

Nhân tiện, lập trình động không có nghĩa là chuyển đổi mã đệ quy thành mã lặp. Bạn cũng có thể lưu các tập hợp con vào một biến nếu bạn muốn một mã đệ quy. Trong trường hợp này, kỹ thuật được gọi là ghi nhớ. Ví dụ của chúng tôi, nó trông như thế này:

// declare and initialize a dictionary
var dict = new Dictionary<int,int>();
for i=1 to n
    dict[i] = -1

function F(n) {
    if (n < 3)
        return 1
    else
    {
        if (dict[n] == -1)
            dict[n] = F(n-1) + F(n-2)

        return dict[n]                
    }
}

Vì vậy, mối quan hệ với Divide và Conquer là thuật toán D & D dựa vào đệ quy. Và một số phiên bản của chúng có "cuộc gọi nhiều chức năng với cùng một vấn đề tham số." Tìm kiếm "nhân chuỗi ma trận" và "chuỗi con chung dài nhất" cho các ví dụ như vậy trong đó DP là cần thiết để cải thiện T (n) của thuật toán D & D.


17

Lập trình động và sự tương đồng giữa phân chia và chinh phục

Như tôi thấy bây giờ tôi có thể nói rằng lập trình động là một phần mở rộng của mô hình phân chia và chinh phục .

Tôi sẽ không coi chúng là một cái gì đó hoàn toàn khác. Bởi vì cả hai đều hoạt động bằng cách chia đệ quy một vấn đề thành hai hoặc nhiều vấn đề phụ cùng loại hoặc liên quan, cho đến khi những vấn đề này trở nên đủ đơn giản để được giải quyết trực tiếp. Các giải pháp cho các vấn đề phụ sau đó được kết hợp để đưa ra giải pháp cho vấn đề ban đầu.

Vậy tại sao chúng ta vẫn có các tên mô hình khác nhau và tại sao tôi gọi lập trình động là một phần mở rộng. Đó là bởi vì phương pháp lập trình động chỉ có thể được áp dụng cho vấn đề nếu vấn đề có những hạn chế hoặc điều kiện tiên quyết nhất định . Và sau đó, lập trình động mở rộng cách tiếp cận phân chia và chinh phục bằng kỹ thuật ghi nhớ hoặc lập bảng .

Hãy đi từng bước một

Điều kiện tiên quyết / hạn chế lập trình động

Như chúng ta vừa phát hiện, có hai thuộc tính chính phân chia và chinh phục vấn đề phải có để áp dụng lập trình động:

  • Cấu trúc  tối ưu - giải pháp tối ưu có thể được xây dựng từ các giải pháp tối ưu của các bài toán con của nó

  • Các vấn đề phụ chồng chéo  - vấn đề có thể được chia thành các bài toán con được sử dụng lại nhiều lần hoặc thuật toán đệ quy cho bài toán giải quyết cùng một bài toán con thay vì luôn tạo ra các bài toán con mới

Một khi hai điều kiện này được đáp ứng, chúng ta có thể nói rằng vấn đề phân chia và chinh phục này có thể được giải quyết bằng cách sử dụng phương pháp lập trình động.

Phần mở rộng lập trình động cho phân chia và chinh phục

Phương pháp lập trình động mở rộng cách tiếp cận phân chia và chinh phục bằng hai kỹ thuật ( ghi nhớlập bảng ) mà cả hai đều có mục đích lưu trữ và sử dụng lại các giải pháp cho các vấn đề phụ có thể cải thiện đáng kể hiệu năng. Ví dụ, việc thực hiện đệ quy ngây thơ của hàm Fibonacci có độ phức tạp về thời gian trong O(2^n)đó giải pháp DP làm tương tự chỉ với O(n)thời gian.

Ghi nhớ (điền vào bộ đệm từ trên xuống) đề cập đến kỹ thuật lưu trữ và sử dụng lại các kết quả được tính toán trước đó. Do đó, fibchức năng ghi nhớ sẽ trông như thế này:

memFib(n) {
    if (mem[n] is undefined)
        if (n < 2) result = n
        else result = memFib(n-2) + memFib(n-1)

        mem[n] = result
    return mem[n]
}

Tabulation (điền vào bộ đệm từ dưới lên) là tương tự nhưng tập trung vào việc điền vào các mục của bộ đệm. Tính toán các giá trị trong bộ đệm được thực hiện lặp đi lặp lại dễ dàng nhất. Phiên bản lập bảng của fibsẽ trông như thế này:

tabFib(n) {
    mem[0] = 0
    mem[1] = 1
    for i = 2...n
        mem[i] = mem[i-2] + mem[i-1]
    return mem[n]
}

Bạn có thể đọc thêm về ghi nhớ và so sánh bảng ở đây .

Ý tưởng chính bạn nên nắm bắt ở đây là bởi vì vấn đề phân chia và chinh phục của chúng ta có các vấn đề phụ chồng chéo, việc lưu bộ đệm của các giải pháp cho vấn đề phụ trở nên khả thi và do đó ghi nhớ / lập bảng bước lên hiện trường.

Vì vậy, sự khác biệt giữa DP và DC sau tất cả

Vì hiện tại chúng tôi đã quen thuộc với các điều kiện tiên quyết của DP và các phương pháp của nó, chúng tôi sẵn sàng đưa tất cả những gì được đề cập ở trên vào một bức tranh.

Lập trình động so với phân chia và chinh phục

Nếu bạn muốn xem các ví dụ về mã, bạn có thể xem phần giải thích chi tiết hơn ở đây nơi bạn sẽ tìm thấy hai ví dụ thuật toán: Tìm kiếm nhị phân và Khoảng cách chỉnh sửa tối thiểu (Khoảng cách Levenshtein) minh họa sự khác biệt giữa DP và DC.


1
Offtopic: Bạn đã sử dụng một máy tính bảng đồ họa để vẽ nó?
Geon George

1
@GeonGeorge không, bản vẽ được thực hiện bằng bút và sau đó được quét
Oleksii Trekhleb

đây là một trong những câu trả lời hay nhất mà tôi đã đọc về việc tổ chức DP
Ridhwaan Shakeel

8

Tôi cho rằng bạn đã đọc Wikipedia và các tài nguyên học thuật khác về điều này, vì vậy tôi sẽ không tái chế bất kỳ thông tin nào trong số đó. Tôi cũng phải cảnh báo rằng tôi không phải là chuyên gia khoa học máy tính, nhưng tôi sẽ chia sẻ hai xu của mình về sự hiểu biết của tôi về những chủ đề này ...

Lập trình năng động

Phá vỡ vấn đề thành các bài toán con rời rạc. Thuật toán đệ quy cho chuỗi Fibonacci là một ví dụ về Lập trình động, bởi vì nó giải quyết cho xơ (n) bằng cách giải quyết đầu tiên cho xơ (n-1). Để giải quyết vấn đề ban đầu, nó giải quyết một vấn đề khác .

Phân chia và chinh phục

Các thuật toán này thường giải quyết các phần tương tự của vấn đề, và sau đó đặt chúng ở cuối. Mergesort là một ví dụ cổ điển về sự phân chia và chinh phục. Sự khác biệt chính giữa ví dụ này và ví dụ Fibonacci là trong một phép hợp nhất, sự phân chia có thể (về mặt lý thuyết) là tùy ý và cho dù bạn cắt nó như thế nào, bạn vẫn đang hợp nhất và sắp xếp. Cùng một lượng công việc phải được thực hiện để hợp nhất mảng, bất kể bạn chia nó như thế nào. Giải quyết cho xơ (52) đòi hỏi nhiều bước hơn so với giải quyết cho xơ (2).


5

Tôi nghĩ về Divide & Conquermột cách tiếp cận đệ quy và Dynamic Programmingđiền vào bảng.

Ví dụ, Merge Sortlà một Divide & Conquerthuật toán, vì trong mỗi bước, bạn chia mảng thành hai nửa, gọi đệ quy Merge Sorthai nửa và sau đó hợp nhất chúng lại.

Knapsacklà một Dynamic Programmingthuật toán khi bạn điền vào một bảng biểu diễn các giải pháp tối ưu cho các bài toán con của chiếc ba lô tổng thể. Mỗi mục trong bảng tương ứng với giá trị tối đa bạn có thể mang theo trong một túi có trọng lượng w cho các mục 1-j.


1
Mặc dù điều này đúng với rất nhiều trường hợp, nhưng không phải lúc nào chúng ta cũng lưu trữ kết quả của các bài toán con trong một bảng.
Gokul

2

Phân chia và chinh phục bao gồm ba bước ở mỗi cấp đệ quy:

  1. Chia vấn đề thành các bài toán con.
  2. Chinh phục các bài toán con bằng cách giải chúng một cách đệ quy.
  3. Kết hợp giải pháp cho các bài toán con thành giải pháp cho bài toán ban đầu.
    • Đó là một cách tiếp cận từ trên xuống .
    • Nó làm việc nhiều hơn trên các bài toán con và do đó có nhiều thời gian hơn.
    • ví dụ. thuật ngữ thứ n của chuỗi Fibonacci có thể được tính theo độ phức tạp thời gian O (2 ^ n).

Lập trình động bao gồm bốn bước sau:

1. Đặc trưng cấu trúc của các giải pháp tối ưu.
2. Xác định đệ quy các giá trị của các giải pháp tối ưu.
3. Tính giá trị của các giải pháp tối ưu.
4. Xây dựng một giải pháp tối ưu từ thông tin được tính toán .

  • Đó là một cách tiếp cận từ dưới lên .
  • Tiêu thụ ít thời gian hơn so với phân chia và chinh phục vì chúng tôi sử dụng các giá trị được tính toán trước đó, thay vì tính toán lại.
  • ví dụ. thuật ngữ thứ n của chuỗi Fibonacci có thể được tính theo độ phức tạp thời gian O (n).

Để dễ hiểu hơn, hãy xem phân chia và chinh phục như một giải pháp vũ phu và tối ưu hóa nó như là lập trình động.

Các thuật toán phân chia và chinh phục NB với các bài toán con chồng chéo chỉ có thể được tối ưu hóa với dp.


Phân chia và chinh phục là từ dưới lên và Lập trình động là từ trên xuống
Bahgat Mashaly

0
  • Phân chia và chinh phục
    • Họ đã phá vỡ các vấn đề phụ không chồng chéo
    • Ví dụ: số giai thừa tức là fact (n) = n * fact (n-1)
fact(5) = 5* fact(4) = 5 * (4 * fact(3))= 5 * 4 * (3 *fact(2))= 5 * 4 * 3 * 2 * (fact(1))

Như chúng ta có thể thấy ở trên, không có thực tế (x) nào được lặp lại nên giai thừa không có vấn đề chồng chéo.

  • Lập trình năng động
    • Họ đã phá vỡ các vấn đề phụ chồng chéo
    • Ví dụ: Số Fibonacci tức là sợi (n) = sợi (n-1) + sợi (n-2)
fib(5) = fib(4) + fib(3) = (fib(3)+fib(2)) + (fib(2)+fib(1))

Như chúng ta có thể thấy ở trên, cả sợi (4) và sợi (3) đều sử dụng sợi (2). tương tự như vậy rất nhiều sợi (x) được lặp lại. đó là lý do tại sao Fibonacci có các vấn đề phụ chồng chéo.

  • Do sự lặp lại của vấn đề phụ trong DP, chúng ta có thể giữ các kết quả như vậy trong một bảng và lưu nỗ lực tính toán. điều này được gọi là ghi nhớ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.