Định kỳ và tạo hàm trong thuật toán


18

Combinatorics đóng một vai trò quan trọng trong khoa học máy tính. Chúng tôi thường xuyên sử dụng các phương pháp tổ hợp trong cả phân tích cũng như thiết kế các thuật toán. Ví dụ: một phương pháp để tìm bìa -vertex được đặt trong biểu đồ có thể chỉ kiểm tra tất cả các tập con có thể có của . Trong khi các hàm nhị thức tăng theo cấp số nhân, nếu k là một hằng số cố định, chúng ta sẽ kết thúc bằng thuật toán thời gian đa thức bằng phân tích tiệm cận.k(nk)k

Thông thường các vấn đề thực tế đòi hỏi các cơ chế tổ hợp phức tạp hơn mà chúng ta có thể định nghĩa theo các đợt tái phát. Một ví dụ nổi tiếng là chuỗi Wikipedia (ngây thơ) được định nghĩa là:

f(n)={1if n=10if n=0f(n1)+f(n2)otherwise

Bây giờ tính toán giá trị của thuật ngữ thứ n tăng theo cấp số nhân bằng cách sử dụng sự lặp lại này, nhưng nhờ lập trình động, chúng tôi có thể tính toán nó theo thời gian tuyến tính. Bây giờ, không phải tất cả các đợt tái phát đều cho DP (ngoài chức năng, chức năng giai thừa), nhưng nó là một thuộc tính có thể khai thác khi xác định một số tính là tái phát thay vì hàm tạo.

Tạo các hàm là một cách thanh lịch để chính thức hóa một số lượng cho một cấu trúc nhất định. Có lẽ nổi tiếng nhất là hàm tạo nhị thức được định nghĩa là:

(x+y)α=k=0(αk)xαkyk

May mắn điều này có một giải pháp hình thức kín. Không phải tất cả các chức năng tạo cho phép một mô tả nhỏ gọn như vậy.

Bây giờ câu hỏi của tôi là: tần suất tạo các hàm được sử dụng trong thiết kế thuật toán? Thật dễ dàng để xem làm thế nào họ có thể được khai thác để hiểu tốc độ tăng trưởng được yêu cầu bởi một thuật toán thông qua phân tích, nhưng họ có thể cho chúng ta biết gì về một vấn đề khi tạo ra một phương pháp để giải quyết vấn đề nào đó?

Nếu nhiều lần số lượng tương tự có thể được định dạng lại như một sự lặp lại, nó có thể tự cho vay để lập trình động, nhưng một lần nữa có lẽ cùng một hàm tạo có dạng đóng. Vì vậy, nó không phải là cắt đều.


Nếu hàm tạo ra một công thức (ví dụ: công thức của Binet cho các số Wikipedia) có thể được sử dụng để tính số thay vì sử dụng phép lặp (có lẽ hiệu quả hơn), bạn có xem đó là câu trả lời không?
Aryabhata

Câu trả lời:


11

Tạo các hàm rất hữu ích khi bạn thiết kế các thuật toán đếm. Đó là, không chỉ khi bạn đang tìm kiếm số lượng đối tượng có một thuộc tính nhất định, mà cả khi bạn đang tìm cách liệt kê các đối tượng này (và có lẽ, tạo ra một thuật toán để đếm các đối tượng). Có một bài trình bày rất hay trong chương 7 của Toán học cụ thể của Ronald Graham, Donald Knuth và Oren Patashnik . Các ví dụ dưới đây là từ những cuốn sách này (những sai lầm và thiếu rõ ràng là của tôi).

Giả sử rằng bạn đang tìm cách để thay đổi với một bộ tiền xu nhất định. Ví dụ: với các mệnh giá phổ biến của Hoa Kỳ¹, các đồng tiền có thể là . Để thay đổi ¢ 42, một khả năng là ; một khả năng khác là . Chúng tôi sẽ viết . Tổng quát hơn, chúng ta có thể viết hàm tạo cho tất cả các cách để thay đổi: Theo thuật ngữ kỹ thuật hơn, là một thuật ngữ trong không gian của chuỗi lũy thừa trong năm biến[1],[5],[10],[25],[100][25][10][5][1][1][10][10][10][10][1][1]42[25][10][5][1]2=[10]4[1]2

H=h0q0d0n0p0[100]h[25]q[10]d[5]n[1]p
H[100],[25],[10],[5],[1]. Xác định giá trị của một đơn thức trong không gian này bằng Sau đó, các cách để thay đổi xu là số lượng đơn thức có định giá là . Chúng ta có thể diễn đạt theo cách tăng dần, bằng cách trước tiên viết ra các cách chỉ thay đổi đồng xu, sau đó là cách để thay đổi đồng xu và biệt hiệu, v.v. ( có nghĩa là không có tiền.)
[100]h[25]q[10]d[5]n[1]p=100h+25q+10d+5n+p
vvHPNI
P=I+[1]+[1]2+[1]3+=II[1]N=(I+[5]+[5]2+[5]3+)P=PI[5]D=(I+[10]+[10]2+[10]3+)N=NI[10]Q=(I+[25]+[25]2+[25]3+)D=DI[25]H=(I+[100]+[100]2+[100]3+)Q=QI[100]
Nếu bạn muốn đếm và không chỉ liệt kê các cách để thay đổi, thì có một cách đơn giản để sử dụng chuỗi chính thức mà chúng tôi đã thu được. Áp dụng phép đồng hình Hệ số của trong là số cách để thay đổi xu.
S:[1]X,[5]X5,[10]X10,[25]X25,[100]X100
XvS(C)v

Một ví dụ khó hơn: giả sử rằng bạn muốn nghiên cứu tất cả các cách để xếp hình chữ nhật với domino 2 × 1. Ví dụ: có hai cách để xếp hình chữ nhật 2 × 2, với hai domino ngang hoặc với hai domino dọc. Đếm số cách để xếp hình chữ nhật khá dễ dàng, nhưng trường hợp nhanh chóng trở nên không rõ ràng. Chúng ta có thể liệt kê tất cả các độ nghiêng có thể có của một dải ngang có chiều cao 3 bằng cách gắn các khối domino lại với nhau, điều này nhanh chóng tạo ra các mẫu lặp đi lặp lại: 2×n3×n

{U=o+LV+ΓΛ+UV=IU+=VΛ=IU+=Λ
trong đó các hình dạng ngộ nghĩnh đại diện cho các sắp xếp domino cơ bản: không phải là domino, là một domino thẳng đứng ở phía trên phần bên trái của một domino nằm ngang, là một domino thẳng đứng được xếp thẳng hàng với đáy của dải có chiều cao 3, là một domino nằm ngang được xếp thẳng hàng với đỉnh của dải cộng với hai domino nằm ngang bên dưới nó và một bước ở bên phải, v.v ... Ở đây, phép nhân biểu thị phép nối ngang và không giao hoán, nhưng có các phương trình giữa các mẫu cơ bản tạo thành các biến trong chuỗi lũy thừa này. Như trước đây với các đồng tiền, chúng ta có thể thay thế cho mỗi domino và nhận được một chuỗi tạo cho số lượng nghiêng của mộtoLI=X3×(2n/3)Hình chữ nhật (tức là hệ số của là số cách để xếp hình chữ nhật có diện tích , chứa domino và có chiều rộng ). Bộ này cũng có thể được sử dụng theo những cách linh hoạt hơn; ví dụ, bằng cách phân biệt các domino dọc và ngang, chúng ta có thể đếm các nghiêng với một số lượng domino dọc và ngang nhất định.X3k6k3k2k

Một lần nữa, đọc Toán học cụ thể để trình bày ít vội vàng hơn.

¹ Tôi biết danh sách của tôi là không đầy đủ; giả sử một nước Mỹ đơn giản hóa phù hợp với các ví dụ toán
học.² ² Ngoài ra, nếu nó xuất hiện, giả sử các đồng tiền hình cầu.
³ Và typeset tốt hơn.


8

Tôi nhớ một vấn đề tôi phải giải quyết trong một cuộc thi lập trình sinh viên năm 2001. Vấn đề là vấn đề này:

Cho các khối lượng 1, 7, 13, ... (Tôi không nhớ khối lượng nào, nhưng có một khối lượng hữu hạn, xác định), thiết kế một hàm xác định xem trọng lượng cho trước có thể được cân trên thang đo này không tập hợp quần chúng.

Tôi bắt đầu với các vòng lặp lồng nhau, nhưng nhanh chóng đập vào tường. Sau đó tôi nhận ra rằng tôi phải bắt đầu với việc liệt kê những gì có thể làm với khối lượng nhẹ hơn trước khi tiếp tục với những người nặng hơn. Tôi có thể giải quyết vấn đề với rất nhiều vòng lặp chưa được kiểm chứng.

Lúc đó tôi không kiêu ngạo và tự lập (và tôi đã biết và thực hành các hàm tạo), tôi có thể đã xác định vấn đề với việc tạo các hàm như sau:

Xác định là OGF cho số cách có thể cân trọng lượng với tập hợp khối lượng.f(x)n

Trọng lượng trên chảo phải tôi có thể cân cho một khối lượng duy nhất là 1?

Ba khả năng:

  • Nếu tôi đặt khối lượng vào chảo bên trái, tôi có thể nặng 1.
  • Nếu tôi đặt khối lượng vào chảo bên phải, tôi có thể cân -1.
  • Nếu tôi không sử dụng khối lượng, tôi có thể cân 0.

Vì vậy, có một cách để cân , một cách để cân và một cách để cân . Hàm tạo cho khối này giống như , tương ứng với:101x1+1+x

1x3x(1x)

Hàm tạo cho một khối lượng duy nhất là , đó là:mxm+1+xm

1x3mxm(1xm)

Cho một khối lượng đa khối, được biểu diễn dưới dạng tích số của các hàm tạo khối đơn lẻ:Mf

f(x)=mM(1x3m)xmMmmM(1xm)

Bây giờ, được cung cấp một gói có thể thực hiện các hoạt động trên đa thức, bạn chỉ cần:

  • Tính cả hai sản phẩm.
  • Thực hiện việc phân chia các sản phẩm này, bắt đầu với mức độ thấp nhất. (chấm dứt)
  • Thay đổi đa thức (phân chia số nhân cho , giữ thương số và bỏ phần còn lại)xk

Và bạn đã hoàn thành. Bây giờ đa thức của bạn có số cách để cân tại chỉ mục . Các đầu vào chỉ là MultiSet của khối .w0wM

Tôi đã thiết kế thuật toán bằng các thành phần âm thanh toán học. Phần chính của thuật toán, là một phép chia đa thức với mức độ thấp nhất trước tiên, là tuyến tính và có thể được thực hiện bằng một gói ngoài luồng. Nó có thể không tối ưu, nhưng chắc chắn nó hoạt động tốt hơn những gì tôi đã làm tại cuộc thi, và theo cách ít bị lỗi hơn.

Nếu bạn nhìn kỹ vào quá trình phân chia, bạn sẽ nhanh chóng thấy rằng phần còn lại có thể được xem là "trạng thái ẩn hiện tại" ở mọi trạng thái của quá trình và kết quả là thương số. Quá trình chấm dứt khi "trạng thái ẩn hiện tại" đạt đến không ở mọi nơi.

Bạn có thể triển khai đa thức dưới dạng mảng hoặc, nếu chúng thực sự thưa thớt, như danh sách theo thứ tự hệ số chỉ mục, và điều này sẽ không thay đổi thuật toán.


3

Trong khi phát triển một thuật toán để tối đa hóa mô đun đơn cực trên matroid, chúng tôi đã phải giải quyết sự tái phát Sau khi nhận thấy rằng , chúng tôi đã giảm vấn đề để tính toán một số chuỗi phổ quát . Cái sau được thực hiện bằng cách sử dụng các hàm tạo và từ đó chúng ta có một công thức rõ ràng cho , một lần nữa sử dụng các hàm tạo. Bạn có thể tìm thấy giải pháp trong bài báo nếu bạn tò mò, mặc dù chúng tôi không bao giờ bận tâm đến việc phát sinh này.

γ+1(m)=(2m)γ(m)+(m+1)γ1(m),γ0(m)=1,γm+1(m)=e.
γ(m)=m(γ(m1)γ1(m1))γ(0)γ(m)

0

Có lẽ nghiên cứu sâu rộng về Quicksort, và nhiều biến thể của nó, là ví dụ rõ ràng nhất. Có các cân nhắc tổ hợp chi phối việc xem xét các phương án và phân tích các giải pháp cho các phương trình khá phức tạp cho thấy lợi thế về hiệu suất (hoặc không) của chúng.

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.