1. Trang chủ
  2. » Kỹ Thuật - Công Nghệ

Bài giảng Thiết kế và đánh giá thuật toán

201 11 0

Đ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

Định dạng
Số trang 201
Dung lượng 1,13 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Cấu trúc

  • Chương 1. Tổng quan về thiết kế và đánh giá thuật toán 1 (7)
    • 1.1. Thuật toán 1 (7)
      • 1.1.1. Khái niệm thuật toán 1 (7)
      • 1.1.2. Các đặc trưng cơ bản của thuật toán 1 (0)
    • 1.2. Sự cần thiết của thiết kế và đánh giá thuât toán 2 (8)
    • 1.3. Diễn tả thuật toán 3 (9)
    • 1.4. Thiết kế thuật toán 7 (13)
      • 1.4.1. Modul hoá và thiết kế từ trên xuống 7 (13)
      • 1.4.2. Phương pháp là mịn dần (tinh chỉnh từng bước) 7 (0)
      • 1.4.3. Một số kỹ thuật thiết kế 8 (14)
    • 1.5. Phân tích thuật toán 9 (0)
      • 1.5.1. Thời gian thực hiên thuật toán 9 (0)
      • 1.5.2. Độ phức tạp tính toán của thuật toán 10 (16)
      • 1.5.3. Ð ộ ph ứ c t ạ p c ủa chương trình có gọi chương trình con không đệ qui 16 (21)
      • 1.5.4. Phân tích các thu ật toán đệ quy 17 (23)
    • 1) Thành l ập phương trình truy hồ i 18 (24)
    • 2) Giải phương trình truy hồi 19 (25)
  • Chương 2. Kỹ thu ật chia để tr ị 37 (43)
    • 2.1 N ộ i dung k ỹ thu ậ t 37 (0)
    • 2.2. Các ví d ụ áp d ụ ng 37 (43)
      • 2.2.1. Tìm min và max 37 (43)
      • 2.2.2. M ộ t s ố thu ậ t toán s ắ p x ế p 40 (46)
    • 1) S ắ p x ế p nhanh 40 (0)
    • 2) S ắ p x ế p tr ộ n 44 (50)
      • 2.2.3. Tìm ki ế m nh ị phân 51 (57)
      • 2.2.4. Nhân các s ố nguyên l ớ n 53 (59)
  • Chương 3. Kỹ thu ậ t tham lam 62 (92)
    • 3.1. N ộ i dung k ỹ thu ậ t 62 (0)
      • 3.1.2. Nội dung kỹ thuật tham lam 62 (0)
    • 3.2. Các ví dụ áp dụng 62 (68)
      • 3.2.1. Bài toán người giao hàng 62 (0)
      • 3.2.2. Bài toán chiếc ba lô 65 (71)
      • 3.2.3. Bài toán tô màu bản đồ 70 (76)
      • 3.2.4. Tìm cây khung nhỏ nhất 74 (80)
      • 3.2.5. T ìm đường đi ngắn nhất 77 (83)
      • 3.2.6. Bài toán phân công công việc 79 (85)
  • Chương 4. Kỹ thuật quay lui 86 (117)
    • 4.1. Nội dung kỹ thuật 86 (92)
    • 4.2. C ác ví dụ áp dụng 87 (93)
      • 4.2.1. Đưa ra các dãy nhị phân độ dài n 87 (0)
      • 4.2.2. Đưa ra các hoán vị của n số nguyên 88 (0)
      • 4.2.4. Bài toán xếp hậu 92 (98)
      • 4.2.5. Tìm đường đi trên đồ thị 94 (100)
      • 4.2.6. Bài toán ngựa đi tuần 99 (105)
  • Chương 5. Kỹ thuật nhánh và cận 111 (0)
    • 5.1. Nội dung kỹ thuật 111 (117)
    • 5.2. Các ví dụ áp dụng 114 (120)
      • 5.2.1. Bài toán người du lịch 114 (120)
      • 5.2.2. Bài toán chiếc ba lô 128 (134)
  • Chương 6. Kỹ thuật quy hoạch động 137 (0)
    • 6.1. Nội dung kỹ thuật 137 (0)
    • 6.2. Các ví dụ áp dụng 140 (146)
      • 6.2.2. Bài toán nhân nhiều ma trận 143 (149)
      • 6.2.3. Bài toán chiếc ba lô 149 (155)
      • 6.2.4. Xâu con chung dài nhất 154 (160)

Nội dung

Tổng quan về thiết kế và đánh giá thuật toán 1

Thuật toán 1

Thuật toán (Algorithm) đã tồn tại từ lâu, ban đầu được hiểu là các quy tắc thực hiện phép tính số học với số trong hệ thập phân Tuy nhiên, cùng với sự phát triển của máy tính, khái niệm này đã mở rộng hơn Hiện nay, thuật toán được định nghĩa một cách chính xác thông qua máy Turing, cho phép chúng ta xem xét khái niệm này một cách trực quan.

Thuật toán (hay giải thuật, thuật giải) là một khái niệm cơ sở của tin học

Mỗi bài toán trong thực tế bao gồm hai phần:

- Input: Các đại lượng cho trước (đại lượng vào)

- Output: Các đại lượng cần tìm (đại lượng ra)

Giải bài toán là quá trình xác định rõ ràng đầu ra (output) dựa trên đầu vào (input) thông qua các thao tác có thể thực hiện hiệu quả Đây là nội dung cốt lõi của lý thuyết tính toán Để giải quyết một bài toán, cần xác định một chuỗi hữu hạn các thao tác đơn giản được sắp xếp theo trình tự nhất định, từ đó giúp chuyển đổi input thành output theo yêu cầu.

Thuật toán giải quyết một bài toán có thể được hình dung như một chuỗi hữu hạn các chỉ dẫn rõ ràng và chính xác, được sắp xếp theo trình tự nhất định Mục tiêu của thuật toán là biến đổi input thành output sau một số lần thực hiện các chỉ dẫn đó.

1.1.2 Các đặc trƣng cơ bản của thuật toán

Mỗi thuật toán có thể có một hoặc nhiều đại lượng vào mà ta thường gọi là dữ liệu vào

Sau khi hoàn thành thuật toán, tùy thuộc vào chức năng mà thuật toán đảm nhận, chúng ta có thể thu được một số đại lượng đầu ra, được gọi là dữ liệu đầu ra.

Tính xác định của thuật toán yêu cầu các thao tác phải rõ ràng và nhất quán ở mỗi bước, tránh sự nhập nhằng hay lẫn lộn Điều này có nghĩa là trong cùng một điều kiện, hai bộ xử lý (có thể là con người hoặc máy móc) phải thực hiện các bước giống nhau một cách chính xác.

Thuật toán phải dừng và cho kết quả sau một số hữu hạn bước thực hiện

Yêu cầu về tính hiệu quả trong việc chọn thuật toán là cần xác định thuật toán tốt nhất trong số các thuật toán thực hiện cùng một chức năng Thuật toán tốt được định nghĩa là thuật toán có khả năng thực hiện nhanh chóng, tiết kiệm thời gian và sử dụng ít bộ nhớ hoặc giấy để lưu trữ các kết quả trung gian.

Một thuật toán được coi là có tính phổ dụng cao khi nó có khả năng giải quyết mọi bài toán trong một lớp các bài toán, thay vì chỉ áp dụng cho một bài toán cụ thể.

Sự cần thiết của thiết kế và đánh giá thuât toán 2

Xây dựng một thuật toán hiệu quả là yếu tố then chốt trong việc giải quyết bài toán trên máy tính Để phát triển một thuật toán tốt, người lập trình cần nắm vững kỹ thuật thiết kế, phân tích và đánh giá thuật toán, cũng như hiểu biết về các thuật toán cơ bản cho các loại bài toán điển hình.

Khi giải một bài toán, có nhiều thuật toán khác nhau có thể được áp dụng, tuy nhiên, việc đánh giá và lựa chọn thuật toán tốt nhất là rất quan trọng Thông thường, chúng ta dựa vào các tiêu chí cụ thể để thực hiện đánh giá này.

Để kiểm tra tính đúng đắn của thuật toán, chúng ta có thể cài đặt và thử nghiệm trên máy với một số bộ dữ liệu mẫu, sau đó so sánh kết quả thu được với kết quả đã biết Tuy nhiên, phương pháp này không hoàn toàn đáng tin cậy, vì thuật toán có thể đúng với các bộ dữ liệu đã thử nhưng lại sai với những bộ dữ liệu khác Hơn nữa, cách làm này chỉ giúp phát hiện sai sót mà không chứng minh được tính đúng đắn của thuật toán Để khẳng định tính đúng đắn, cần có sự chứng minh bằng toán học, điều này không hề đơn giản và sẽ không được đề cập trong bài viết này.

Khi viết chương trình để sử dụng nhiều lần, yêu cầu tiết kiệm thời gian thực hiện trở nên quan trọng, đặc biệt với các chương trình xử lý dữ liệu lớn Trong trường hợp này, hiệu quả thời gian thực hiện của thuật toán cần được xem xét kỹ lưỡng Ngược lại, với các chương trình chỉ sử dụng một vài lần, việc viết thuật toán dễ dàng để nhanh chóng có kết quả là ưu tiên hàng đầu, trong khi thời gian thực hiện không quá quan trọng.

Diễn tả thuật toán 3

Có nhiều cách diễn tả thuật toán Người ta thường diễn tả thuật toán bằng một trong các cách sau:

Thuật toán có thể trình bày dưới dạng ngôn ngữ tự nhiện theo trình tự các bước thực hiện trong thuật toán

Sử dụng hình vẽ có quy ước để mô tả thuật toán là một phương pháp hiệu quả Lưu đồ, với khả năng tạo ra hình ảnh trực quan và tổng thể, thường được ưa chuộng trong việc trình bày các thuật toán.

Dùng cấu trúc lệnh, dữ liệu của một ngôn ngữ lập trình nào đó để mô tả

Thuật toán thường được trình bày dưới dạng văn bản bằng ngôn ngữ tự nhiên, dễ hiểu nhưng khó cài đặt Khi sử dụng ngôn ngữ lập trình, việc diễn tả trở nên phức tạp và khó hiểu Do đó, thuật toán thường được thể hiện dưới dạng giả mã, không ràng buộc nhiều vào cú pháp của ngôn ngữ lập trình nhưng vẫn tuân theo một số quy ước nhất định Tùy thuộc vào ngôn ngữ lập trình mà thuật toán được định hướng, cách diễn đạt sẽ gần gũi hơn với ngôn ngữ đó Trong tài liệu này, các thuật toán sẽ được trình bày dưới dạng giả mã của ngôn ngữ lập trình C, kèm theo một số quy ước của ngôn ngữ này.

- Các dấu phép toán số học.

- Các dấu phép toán quan hệ.

* Các phép toán số học và logic

Các từ sau xem như là các từ khoá : if, else, case, for, while , do while

* Các phép toán số học và logic

- Các phép toán số học : +, -, *, /, %

* Lệnh gán: biến=biểu thức;

* Cấu trúc rẽ nhánh if

Toán tử if là công cụ quan trọng trong lập trình, cho phép lựa chọn giữa hai nhánh thực thi dựa trên giá trị của biểu thức Có hai cách viết cơ bản cho toán tử if: dạng một là "if (biểu thức) khối lệnh 1", và dạng hai là "if (biểu thức) khối lệnh 1 else khối lệnh 2".

Sự lồng nhau của các toán tử if :

C cho phép sử dụng các toán tử if lồng nhau có nghĩa là trong các khối lệnh

Trong các đoạn mã chứa toán tử if - else, việc sử dụng dấu ngoặc để phân chia các khối là rất quan trọng Nếu không sử dụng đúng cách, có thể dẫn đến nhầm lẫn giữa các cấu trúc if-else Lưu ý rằng máy sẽ tự động kết hợp toán tử else với toán tử if gần nhất mà không có else.

* Cấu trúc rẽ nhánh - toán tử switch: switch (biểu thức nguyên)

{ case n1 khối lệnh 1 case n2 khối lệnh 2 case nk khối lệnh k [ default khối lệnh k+1]

Trong lập trình, toán tử switch sử dụng các số nguyên, hằng ký tự hoặc biểu thức hằng với giá trị khác nhau Thân của toán tử switch được xác định bởi đoạn chương trình nằm giữa các dấu { } Thành phần default trong switch là không bắt buộc, nhưng có thể được sử dụng để xử lý các trường hợp không khớp.

* Cấu trúc lặp với toán tử while :

Toán tử while dùng để xây dựng chu trình lặp dạng : while (biểu thức)

Như vậy toán tử while gồm một biểu thức và thân chu trình Thân chu trình có thể là một lệnh hoặc một khối lệnh

Hoạt động của chu trình như sau :

Máy xác định giá trị của biểu thức, tuỳ thuộc giá trị của nó máy sẽ chọn cách thực hiện như sau :

Nếu biểu thức có giá trị 0 (biểu thức sai), máy sẽ ra khỏi chu trình và chuyển tới thực hiện câu lệnh tiếp sau chu trình trong chương trình

Nếu biểu thức trong vòng lặp while có giá trị khác không, máy sẽ thực hiện lệnh hoặc khối lệnh bên trong Sau khi hoàn thành khối lệnh, máy sẽ kiểm tra lại giá trị của biểu thức và tiếp tục thực hiện các bước tương tự.

* Cấu trúc lặp với toán tử for :

Toán tử for dùng để xây dựng cấu trúc lặp có dạng sau : for (biểu thức 1; biểu thức 2; biểu thức 3)

Lệnh hoặc khối lệnh ; Toán tử for gồm ba biểu thức và thân for Thân for là một câu lệnh hoặc một ố ệ ế ừ ấ ỳ ể ứ ể ứ ể vắng mặt nhưng phải giữ dấu ;

Biểu thức 1 thường được sử dụng như toán tử gán để khởi tạo giá trị cho biến điều khiển Biểu thức 2 là một quan hệ logic thể hiện điều kiện cần thiết để tiếp tục chu trình Cuối cùng, biểu thức 3 là toán tử gán được dùng để cập nhật giá trị của biến điều khiển.

Hoạt động của toán tử for :

Toán tử for hoạt động theo các bước sau :

Tuỳ thuộc vào tính đúng sai của biểu thức 2 để máy lựa chọn một trong hai nhánh :

Nếu biểu thức 2 có giá trị 0 (sai), máy sẽ ra khỏi for và chuyển tới câu lệnh sau thân for

Nếu biểu thức 2 có giá trị khác 0 (đúng), máy sẽ thực hiện các câu lệnh trong thân for

Tính biểu thức 3, sau đó quay lại bước 2 để bắt đầu một vòng mới của chu trình

Khác với các toán tử while và for, chu trình do while kiểm tra điều kiện kết thúc ở cuối chu trình, đảm bảo rằng thân chu trình luôn được thực hiện ít nhất một lần.

Lệnh hoặc khối lệnh; while (biểu thức) ;

Hoạt động của chu trình như sau :

Máy thực hiện các lệnh trong thân chu trình

Sau khi hoàn thành tất cả các lệnh trong thân chu trình, máy sẽ xác định giá trị của biểu thức sau từ khóa while và quyết định có thực hiện tiếp hay không.

Nếu biểu thức đúng (khác 0) máy sẽ thực hiện lặp lại khối lệnh của chu trình lần thứ hai rồi thực hiện kiểm tra lại biểu thức như trên

Nếu biểu thức sai (bằng 0) máy sẽ kết thúc chu trình và chuyển tới thực hiện lệnh đứng sau toán tử while

Những điều lưu ý với toán tử while ở trên hoàn toàn đúng với do while

Câu lệnh break cho phép thoát khỏi các vòng lặp như for, while, do while và switch Khi có nhiều vòng lặp lồng nhau, break sẽ đưa chương trình ra khỏi vòng lặp bên trong nhất mà không cần điều kiện nào.

Lệnh continue trái ngược với lệnh break, được sử dụng để bắt đầu một vòng mới trong chu trình Trong các vòng lặp while và do while, lệnh continue sẽ chuyển điều khiển về phần kiểm tra, trong khi đó, trong vòng lặp for, điều khiển sẽ quay về bước khởi đầu lại, tức là tính biểu thức 3 và sau đó trở lại bước 2 để bắt đầu vòng lặp mới Cần lưu ý rằng lệnh continue chỉ áp dụng cho chu trình và không sử dụng cho cấu trúc switch.

Thiết kế thuật toán 7

1.4.1 Modul hoá và thiết kế từ trên xuống

Các bài toán trên máy tính ngày càng phức tạp và đa dạng, đòi hỏi các thuật toán với quy mô lớn và nhiều nguồn lực Để đơn giản hóa quá trình giải quyết, việc chia bài toán thành các phần nhỏ hơn là cần thiết Điều này có nghĩa là bài toán chính cần được phân chia thành các modul con, và các modul này cũng có thể được phân rã thành các modul nhỏ hơn phù hợp.

Việc tổ chức lời giải bài toán theo cấu trúc phân cấp thể hiện chiến thuật “chia để trị” Chiến thuật này sử dụng thiết kế từ trên xuống, cho phép nhìn nhận vấn đề một cách tổng quát, bắt đầu từ các công việc chính và sau đó bổ sung dần các chi tiết cần thiết.

1.4.2 Phương pháp làm mịn dần (tinh chỉnh từng bước) Đầu tiên thuật toán được trình bày dưới dạng ngôn ngữ tự nhiên thể hiện ý chính công việc Các bước sau sẽ chi tiết hóa dần tương ứng với các công việc nhỏ hơn Đó là các bước làm mịn dần đặc tả thuật toán và hướng về ngôn ngữ lập trình mà ta dự định cài đặt.

Quá trình thiết kế và phát triển thuật toán diễn ra qua ba giai đoạn chính: bắt đầu từ ngôn ngữ tự nhiên, chuyển sang ngôn ngữ mã giả, và cuối cùng là ngôn ngữ lập trình Quá trình này không chỉ xác định "làm cái gì" mà còn đi sâu vào "làm như thế nào".

1.4.3 Một số kỹ thuật thiết kế

Dựa trên lý thuyết máy Turing, các bài toán được phân thành hai lớp không giao nhau: lớp bài toán có thể giải bằng thuật toán và lớp bài toán không thể giải bằng thuật toán Đối với lớp bài toán có thể giải, có thể chỉ ra một số kỹ thuật thiết kế thuật toán cơ bản dựa trên các đặc trưng của quá trình thiết kế.

1) Kỹ thuật chia để trị

Chia bài toán thành các bài toán đủ nhỏ, giải các bài toán nhỏ rồi tổng hợp kết quả lại

Tìm kiếm theo ưu tiên là một phương pháp quan trọng trong thuật toán, nơi quyết định lựa chọn giữa tìm kiếm theo độ rộng hoặc chiều sâu Ví dụ, trong giải bài toán 8 hậu, việc áp dụng thuật toán ưu tiên giúp tìm ra các giải pháp hiệu quả hơn.

3) Kỹ thuật tham lam Ý tưởng là : Xác định trật tự xử lý để có lợi nhất, Sắp xếp dữ liệu theo trật tự đó, rồi xử lý dữ liệu theo trật tự đã nêu Công sức bỏ ra là tìm ra trật tự đó Chẳng hạn thuật toán tìm cây khung nhỏ nhất.

4) Kỹ thuật nhánh và cận

Trong quá trình tìm kiếm giải pháp, chúng ta phân chia các phương án của bài toán thành nhiều tập con, được thể hiện dưới dạng các nút trong cây tìm kiếm Bằng cách sử dụng các phép đánh giá cận cho các nút, chúng ta nỗ lực loại bỏ những nhánh trong cây mà chắc chắn không chứa phương án tối ưu.

5) Kỹ thuật Quy hoạch động

Kỹ thuật quy hoạch động dựa vào một nguyên lý, gọi là nguyên lý tối ưu của Bellman :

“ Nếu lời giải của bài toán là tối ưu thì lời giải của các bài toán con cũng tối ưu ”.

Kỹ thuật này áp dụng phương pháp tìm kiếm lời giải từ dưới lên, bắt đầu từ các bài toán con nhỏ và đơn giản Bằng cách kết hợp các lời giải của những bài toán con này, chúng ta dần dần xây dựng được lời giải cho bài toán lớn hơn, cho đến khi đạt được lời giải cho bài toán ban đầu.

Khi giải một bài toán, chúng ta có thể áp dụng nhiều thuật toán khác nhau, tuy nhiên, việc đánh giá và lựa chọn thuật toán tối ưu là rất quan trọng Thông thường, các tiêu chí đánh giá sẽ được căn cứ vào hiệu quả, độ chính xác và tốc độ xử lý của từng thuật toán.

Khi phát triển một chương trình chỉ sử dụng trong một thời gian ngắn, việc chọn lựa thuật toán đơn giản là rất quan trọng Chúng ta cần một giải thuật dễ dàng để lập trình, giúp nhanh chóng đạt được kết quả mong muốn Thời gian thực hiện chương trình không phải là yếu tố ưu tiên, vì chương trình này chỉ được sử dụng một vài lần.

Khi một chương trình được sử dụng nhiều lần, việc tiết kiệm thời gian thực hiện trở nên rất quan trọng, đặc biệt với các chương trình yêu cầu dữ liệu đầu vào lớn Do đó, hiệu quả thời gian thực hiện của thuật toán cần được xem xét kỹ lưỡng Bên cạnh đó, với khối lượng dữ liệu lớn và dung lượng bộ nhớ hạn chế, yêu cầu tiết kiệm bộ nhớ cũng không thể bị bỏ qua Tuy nhiên, việc cân bằng giữa yêu cầu về thời gian và không gian thường không dễ dàng đạt được một giải pháp hoàn hảo.

Sau đây ta sẽ chỉ chú ý đến việc phân tích thời gian thực hiện thuật toán

1.5.1 Thời gian thực hiện thuật toỏn

Một cách để đánh giá hiệu quả thời gian thực hiện của một thuật toán là lập trình nó và đo thời gian thực hiện trên một máy tính cụ thể với một tập hợp dữ liệu đầu vào được chọn lọc.

Thời gian thực hiện của thuật toán không chỉ phụ thuộc vào chính thuật toán mà còn vào tập chỉ thị máy tính, chất lượng máy tính và kỹ năng lập trình viên Việc thực thi có thể được tối ưu hóa cho các tập dữ liệu cụ thể Để giải quyết những thách thức này, các nhà khoa học máy tính đã công nhận rằng tính phức tạp thời gian là một chỉ số quan trọng để đánh giá hiệu suất của thuật toán, đặc biệt là trong trường hợp xấu nhất.

Thời gian thực hiện của thuật toán không chỉ phụ thuộc vào kích thước của dữ liệu mà còn vào tính chất của dữ liệu đầu vào Dù dữ liệu có cùng kích thước, thời gian thực hiện có thể khác nhau Ví dụ, trong chương trình sắp xếp dãy số nguyên tăng dần, thời gian thực hiện sẽ khác nhau khi đầu vào là dãy đã có thứ tự so với dãy chưa có thứ tự, hoặc giữa dãy đã sắp xếp tăng và dãy đã sắp xếp giảm.

Thành l ập phương trình truy hồ i 18

Phương trình truy hồi mô tả mối quan hệ giữa T(n) và T(k), với T(n) là thời gian thực hiện chương trình khi kích thước dữ liệu đầu vào là n, và T(k) là thời gian thực hiện khi kích thước dữ liệu đầu vào là k (k < n) Để xây dựng phương trình truy hồi, cần dựa vào chương trình đệ quy.

Một chương trình đệ quy giải quyết bài toán kích thước n cần có ít nhất một trường hợp dừng cho n cụ thể và lời gọi đệ quy cho bài toán kích thước k (k1T(n) if (n 1 cần thực hiện lệnh gán gt= n*Giai_thua(n - 1)

Thời gian T(n) được xác định là O(1) cho các phép nhân và gán, cộng với T(n-1) cho lời gọi đệ quy Giai_thua(n – 1) Tóm lại, ta có mối quan hệ sau:

Thay các O(1) bởi các hằng nào đó, ta nhận được quan hệ sau

T(n) = C2 + T(n - 1) Để giải phương trình truy hồi, tìm T(n), chúng ta áp dụng phương pháp thế lặp Ta có phương trình truy hồi

Thay m lần lượt bởi 2, 3, , n - 1, n, ta nhận được các quan hệ sau:

Bằng các phép thế liên tiếp, ta nhận được

T(n) = (n - 1) C 2 + T(1) hay T(n) = (n - 1) C 2 + C1, trong đó C1 và C2là các hằng nào đó

Giải phương trình truy hồi sau: c 1 nếu n=1

Quá trình sẽ dừng khi: i

 n =2 i  i = log 2 n Khi đó: T(n) = nT(1) + c 2 nlog 2 n

Ta đoán một nghiệm f(n) và dùng chứng minh quy nạp để chứng tỏ rằng T(n)

Hàm f(n) thường được xác định cho mọi n và thường là một trong những hàm quen thuộc như log2n, n, n log2n, n^2, n^3, 2^n, n!, hoặc n^n Đôi khi, chúng ta chỉ có thể phỏng đoán dạng của f(n) với một số tham số chưa xác định, ví dụ như f(n) = an^2 với a chưa được xác định Trong quá trình chứng minh quy nạp, chúng ta sẽ suy diễn ra giá trị thích hợp cho các tham số này.

Ví dụ 1.10 Giải phương trình truy hồi sau:

Giả sử chúng ta đoán f(n) = anlog2n Với n = 1 ta thấy rằng việc đoán như vậykhông được bởi vì anlog2n có giá trị 0 không phụ thuộc vào giá trị của a

Vì thế tathử tiếp theo f(n) = anlog 2 n + b

Với n = 1 ta có, T(1) = C1 và f(1) = b, muốn T(1) ≤ f(1) thì b ≥ C1 (*)

Giả sử rằng T(k) ≤ f(k), tức là T(k) ≤ aklog2k + b với mọi k < n (giả thiết quy nạp).

Ta phải chứng minh T(n) ≤ anlog2n + b với mọi n.

Giả sử n ≥ 2, từ phương trình đã cho ta có T(n) = 2T(

2 n )+ c2n Áp dụng giả thiết quy nạp với k 2 n ta có

≤ (anlog2n + b) + [b + (c 2 - a)n] Nếu lấy a ≥ c 2 + b (**) ta được

Nếu ta lấy a và b sao cho cả (*) và (**) đều thoả mãn

Tức là: b  c1 a  c 2 + b thì T(n) ≤ anlog2n + b với mọi n

Như vậy với b  c 1 và a  c 1 + c 2 thì ta sẽ có T(n) ≤ (c1 + c 2 )nlog 2 n +c 1 với mọi n. Hay nói cách khác T(n) là O(nlog 2 n)

* Phương pháp dùng phương trình đặc trưng với phương trình truy hồi tuyến tính thuần nhất hệ số hằng

Phương trình truy hồi (công thức truy hồi) tuyến tính thuần nhất bậc k với hệ số hằng số có dạng:

T(n) a n = c 1 a n-1 + c 2 a n-2 + + c k a n-k trong đó c 1 , c 2 , , c k là các số thực, c k  0

Nếu được cung cấp các điều kiện ban đầu a 0 = c 0, a 1 = c 1, , a k-1 = c k-1, thì theo quy tắc quy nạp toán học, dãy số thỏa mãn phương trình truy hồi trong định nghĩa sẽ được xác định một cách duy nhất.

Phương pháp cơ bản để giải phương trình truy hồi tuyến tính thuần nhất là tìm nghiệm dạng a_n = r^n, với r là hằng số Nghiệm a_n = r^n thỏa mãn phương trình a_n = c_1 a_{n-1} + c_2 a_{n-2} + + c_k a_{n-k khi và chỉ khi r^n = c_1 r^{n-1} + c_2 r^{n-2} + + c_k r^{n-k Điều này dẫn đến phương trình đặc trưng: r^n - c_1 r^{n-1} - c_2 r^{n-2} - - c_k r^{n-k = 0.

Dãy {an} với an = r^n là nghiệm của phương trình đại số khi và chỉ khi r là nghiệm của phương trình đặc trưng của công thức truy hồi Nghiệm của phương trình này được gọi là nghiệm đặc trưng và sẽ được sử dụng để tìm công thức tường minh cho tất cả các nghiệm của phương trình truy hồi Đối với phương trình truy hồi tuyến tính thuần nhất bậc 2, khi phương trình đặc trưng có hai nghiệm phân biệt r1 và r2, dãy số {an} sẽ là nghiệm của công thức truy hồi an = c1 an-1 + c2 an-2 khi và chỉ khi an = α1 r1^n + α2 r2^n, với n = 0, 1, 2, , trong đó α1 và α2 là các hằng số.

Ngược lại, giả sử {an} là một nghiệm bất kỳ của phương trình truy hồi, ta sẽ chọn 1 và 2 sao cho dãy {an} với an = a1r1 n

+ a2r2 n thoả mãn các điều kiện đầu a0

Từ phương trình đầu ta được 2 = c0 - 1 Thay vào phương trình sau ta được: c 1 = a 1 r 1 + (c 0 -  1 )r 2 = a 1 (r 1 - r 2 ) + c 0 r 2

Khi lựa chọn các giá trị a1 và a2, dãy {an} với an = a1 r1^n + a2 r2^n sẽ thỏa mãn các điều kiện ban đầu Do phương trình truy hồi cùng các điều kiện đầu xác định duy nhất, ta có thể khẳng định rằng an = a1 r1^n + a2 r2^n.

Giả sử rằng các con thỏ không bao giờ chết, bắt đầu với một cặp thỏ vào tháng đầu Sau 2 tháng, cặp thỏ này sẽ sinh ra một cặp thỏ mới và từ đó mỗi tháng sẽ tiếp tục sinh ra một cặp thỏ mới Vậy, nếu tính đến tháng thứ n, số lượng cặp thỏ sẽ tăng lên đáng kể.

Số cặp thỏ ở tháng thứ n, được ký hiệu là Fn, được xác định với điều kiện F1 = F2 = 1 Đối với n > 2, số cặp thỏ ở tháng thứ n sẽ bằng tổng số cặp thỏ ở tháng thứ n-1 và tháng thứ n-2.

Fn -1 ) cộng với số cặp thỏ mới được sinh ra ở tháng thứ n - chính là số cặp thỏ có ở tháng thứ n-2 (là Fn -2 ) Tức là:

Vì vậy có thể tính Fn theo hệ thức truy hồi sau:

Dãy số thể hiện Fn với các giá trị của n được gọi là dãy số Fibonacci

Từ hệ thức truy hồi trên ta dễ dàng có được giải thuật sau để tính số cặp thỏ có ở tháng thứ n

{ if(n2T(n) Giải phương trình đặc trưng r 2 - r- 1 = 0 ta thu được hai nghiệm:

Khi đó ta có T(n) =  1 r 1 n +  2 r 2 n (*) trong đó  1 ,  2 là các hằng số cần xác định từ các giá trị ban đầu T(1) và T(2) Thay T(1) và T(1) vào (*) và giải ra ta được

Như vậy độ phức tạp tính toán của giải thuật là cấp hàm mũ

Bài viết này trình bày các phương pháp giải phương trình truy hồi, bao gồm hệ thức và công thức truy hồi, giúp người đọc dễ dàng áp dụng để xác định độ phức tạp tính toán của các thuật toán tương ứng.

Tìm nghiệm của công thức truy hồi a n = a n-1 + 2a n-2 , với a 0 = 2, a 1 = 7

Phương trình đặc trưng của công thức truy hồi có dạng r² - r - 2 = 0, với nghiệm là r = 2 và r = -1 Theo định lý, dãy {an} là nghiệm của công thức truy hồi khi và chỉ khi an = α₁ * 2ⁿ + α₂ * (-1)ⁿ, với các hằng số α₁ và α₂ Từ các điều kiện đầu, ta có a₀ = 2 = α₁ + α₂ và a₁ = 7 = α₁ * 2 + α₂ * (-1).

Giải ra ta được  1 = 3 và  2 = -1 Vậy nghiệm của công thức truy hồi với điều kiện đầu là dãy {an} với an = 3.2 n - (-1) n

Khi phương trình đặc trưng của công thức truy hồi tuyến tính thuần nhất bậc 2 có nghiệm bội (chỉ có một nghiệm r0), thì dãy số {an} là nghiệm của công thức truy hồi an = c1 a n-1 + c2 a n-2 khi và chỉ khi an = α1 r0^n + α2 n r0^n, với n = 0, 1, 2, , trong đó α1 và α2 là các hằng số.

Tìm nghiệm của hệ thức truy hồi a n = 6a n-1 - 9a n-2 với các điều kiện ban đầu a 0 = 1 và a 1 =6

Phương trình đặc trưng r² - 6r + 9 = 0 có nghiệm kép r = 3, dẫn đến nghiệm của hệ thức truy hồi có dạng an = ₁ 3ⁿ + ₂ n 3ⁿ Từ điều kiện đầu a₀ = 1 và a₁ = 6, ta suy ra ₁ = 1 và ₂ = 1 Do đó, nghiệm của hệ thức truy hồi cùng với các điều kiện ban đầu là an = 3ⁿ + n 3ⁿ.

Khi tổng quát hóa kết quả cho hệ thức truy hồi tuyến tính thuần nhất với hệ số hằng bậc k > 2, giả sử phương trình đặc trưng rk - c1 rk -1 - c2 rk -2 - - ck = 0 có k nghiệm phân biệt r1, r2, , rk Dãy số {an} là nghiệm của hệ thức truy hồi an = c1 an-1 + c2 an-2 + + ck an-k nếu và chỉ nếu an = α1 r1^n + α2 r2^n + + αk rk^n với n = 0, 1, 2, , trong đó α1, α2, , αk là các hằng số.

Tìm nghiệm của hệ thức an = 6an-1- 11an-2 + 6an-3 với điều kiện đầu a0 = 2, a1

Giải: Phương trình đặc trưng r 3 - 6r 2 + 11r- 6 = 0 có 3 ngiệm r 1 = 1, r 2 = 2, r 3 = 3 Vì vậy, nghiệm có dạng a n =  1 1 n +  2 2 n + 3 3 n

Sử dụng các điều kiện đầu ta có 1=1, 2 =-1, 3 = 2 Vậy nghiệm của hệ thức đã cho là an = 1- 2 n +2.3 n

* Phương trình truy hồi có dạng:

(1 Để xác định độ phức tạp tính toán của thuật toán theo phương trình truy hồi trên ta thực hiên như sau:

Chia bài toán kích thước n thành các bài toán con có kích thước n/b và giải quyết từng bài toán con này Sau khi tổng hợp kết quả, ta sẽ có lời giải cho bài toán ban đầu Áp dụng kỹ thuật tương tự cho các bài toán con sẽ dẫn đến kích thước bài toán con cuối cùng là 1, từ đó hình thành một giải thuật đệ quy hiệu quả.

Kỹ thu ật chia để tr ị 37

Kỹ thu ậ t tham lam 62

Kỹ thuật quay lui 86

Kỹ thuật nhánh và cận 111

Kỹ thuật quy hoạch động 137

Ngày đăng: 13/10/2021, 13:14

🧩 Sản phẩm bạn có thể quan tâm

w