Bỏ qua các yếu tố phần cứng của công nghệ hiện hành các bài toán được giải trên máy tính phải có thuật toán để xử lý và theo Alan Turing, tất cả các thuật toán đều có thể mô tả lại trên
Trang 1TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG
NGUYỄN ANH TÙNG
CÀI ĐẶT MÁY TURING
VÀ ỨNG DỤNG MÁY TURING ĐÁNH GIÁ ĐỘ PHỨC TẠP THUẬT TOÁN
LUẬN VĂN THẠC SĨ KHOA HỌC MÁY TÍNH
THÁI NGUYÊN - 2015
Trang 2TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG
NGUYỄN ANH TÙNG
CÀI ĐẶT MÁY TURING
VÀ ỨNG DỤNG MÁY TURING ĐÁNH GIÁ ĐỘ PHỨC TẠP THUẬT TOÁN
Chuyên ngành: KHOA HỌC MÁY TÍNH
Mã số: 60480101
LUẬN VĂN THẠC SĨ KHOA HỌC MÁY TÍNH
Người hướng dẫn khoa học: PGS.TSKH NGUYỄN XUÂN HUY
THÁI NGUYÊN - 2015
Trang 3LỜI CAM ĐOAN
Tôi xin cam đoan luận văn này do chính tôi thực hiện, dưới sự hướng dẫn khoa học của PGS.TSKH Nguyễn Xuân Huy, số liệu và kết quả nghiên cứu trong luận văn này hoàn toàn trung thực và chưa sử dụng để bảo vệ một công trình khoa học nào, các thông tin, tài liệu trích dẫn trong luận văn
đã được chỉ rõ nguồn gốc Mọi sự giúp đỡ cho việc hoàn thành luận văn đều đã được cảm ơn Nếu sai tôi hoàn toàn chịu trách nhiệm
Thái Nguyên, tháng 8 năm 2015
Tác giả
Nguyễn Anh Tùng
Trang 4LỜI CẢM ƠN
Em xin gửi lời cảm ơn chân thành nhất đến thầy giáo PGS.TSKH Nguyễn
Xuân Huy đã định hướng và nhiệt tình hướng dẫn, giúp đỡ em trong quá trình
Thái Nguyên, tháng 8 năm 2015
Học viên
Nguyễn Anh Tùng
Trang 5MỤC LỤC
LỜI CAM ĐOAN i
LỜI CẢM ƠN ii
MỤC LỤC iii
DANH MỤC BẢNG BIỂU, HÌNH VẼ v
MỞ ĐẦU 1
Chương 1 TỔNG QUAN MÔ HÌNH MÁY TURING 1
1.1 Giới thiệu chung 1
1.2 Cấu trúc máy Turing 2
1.3 Hoạt động của máy Turing 6
1.4 Trạng thái và sơ đồ trạng thái của máy Turing 7
1.5 Máy Turing và định nghĩa thuật toán 14
1.5.1 Độ phức tạp thuật toán 14
1.5.2 Ứng dụng máy Turing để đo độ phức tạp thuật toán 20
1.6 Kết luận 21
Chương 2 CÀI ĐẶT MÁY TURING NGUYÊN THỦY VÀ MỘT SỐ CẢI TIẾN 22
2.1 Cài đặt Máy Turing 22
2.1.1 Giao diện chương trình 27
2.1.2 Cấu trúc dữ liệu đầu vào 30
2.1.3 Các hàm xử lí dữ liệu 34
2.2 Phát triển bộ nhớ máy Turing 36
2.2.1 Máy Turing nhiều băng 36
2.2.2 Cài đặt cấu trúc ngăn xếp (Stack) 37
2.2.3 Cài đặt cấu trúc hàng đợi (Queue) 38
2.2.4 Cài đặt bộ nhớ imem và cmem 39
2.4 Kết luận 42
Trang 6Chương 3 MỘT SỐ CHƯƠNG TRÌNH ỨNG DỤNG MÁY TURING
ĐO ĐỘ PHỨC TẠP THUẬT TOÁN 43
3.1 Bài toán trừ một vào số tự nhiên 43
3.2 Biểu diễn số thập phân n thành (n+1) vạch | 46
3.3 Biểu diễn (n+1) vạch | thành số tự nhiên n 49
3.4 Cộng hai số tự nhiên lớn 52
3.5 Kết luận 61
KẾT LUẬN 62
TÀI LIỆU THAM KHẢO 63
Trang 7DANH MỤC BẢNG BIỂU, HÌNH VẼ
Bảng
Bảng 1.1 So sánh câu lệnh giữa cách viết thông thường và cách viết gộp 6
Bảng 1.2 Trạng thái máy Turing 10
Hình vẽ Hình 1.1 Mô hình máy Turing 2
Hình 1.2 Mối quan hệ giữa lớp P và NP 18
Hình 1.3 Minh hoạ một phép dẫn bài toán 1 thành 2 trong thời gian đa thức 19
Hình 1.4 Mối quan hệ giữa lớp P, NP và NPC 20
Hình 2.1 Giao diện máy Turing 27
Hình 2.2 Chọn tệp mặc định 27
Hình 2.3 Chọn chương trình do người dùng tạo 28
Hình 2.4 Nhập dữ liệu từ bàn phím 28
Hình 2.5 Hiển thị kết quả 29
Hình 2.6 Hiển thị kết quả trung gian của chương trình 29
Trang 8tự nhất định sao cho sau khi thực hiện dãy thao tác ấy, từ input của bài toán,
ta nhận được output cần tìm Đối với một thuật toán điều rất quan tâm đến đó chính là độ phức tạp của nó, đánh giá càng chính xác độ phức tạp của thuật toán sẽ giúp cho quá trình lựa chọn và sử dụng
Trước khi có máy tính điện tử Alan Turing đã trình bày các mô hình máy Turing vào năm 1936 dành cho các thí nghiệm tưởng tượng để tìm hiểu giới hạn tính toán trên máy móc Tuy không trực tiếp ảnh hưởng tới việc chế tạo máy tính điện tử nhưng máy Turing là một công cụ đo sự hiệu quả của thuật toán của một bài toán cụ thể
Bỏ qua các yếu tố phần cứng của công nghệ hiện hành các bài toán được giải trên máy tính phải có thuật toán để xử lý và theo Alan Turing, tất cả các thuật toán đều có thể mô tả lại trên mô hình máy Turing, vậy việc đánh giá các thuật toán trên máy Turing sẽ cho kết quả chính xác và công bằng nhất
Độ phức tạp thuật toán được đánh giá bằng máy Turing theo hai tiêu chí là: thời gian (số nhịp làm việc của máy Turing) và bộ nhớ (số ô nhớ cần sử dụng trong quá trình máy làm việc)
Trang 9Thời gian (số nhịp làm việc của máy Turing): là số lần dịch chuyển của đầu đọc trên băng
Bộ nhớ (số ô nhớ cần sử dụng trong quá trình máy làm việc): là số ô trên bang mà máy Turing ghi các kí tự trong khi xử lý
Vì vậy học viên chọn đề tài: “Cài đặt máy Turing và ứng dụng máy
Turing đánh giá độ phức tạp thuật toán” với mục đích nghiên cứu một công
cụ đánh giá thuật toán
Nội dung chính của luận văn bao gồm:
Chương 1: Luận văn trình bày tổng quan về máy Turing và các vấn đền
liên quan đến thuật toán
Chương 2: Luận văn cài đặt máy Turing trên ngôn ngữ C++ và cải tiến
một số bộ nhớ tăng hiệu quả làm việc của máy
Chương 3: Luận văn sử dụng máy Turing để giải một số bài toán và
đánh giá độ phức tạp cụ thể từng bài
Trang 10Chương 1
TỔNG QUAN MÔ HÌNH MÁY TURING
Trong chương này của luận văn học viên giới thiệu lại một số định nghĩa
về máy Turing và thuật toán Trong đó có mô tả về máy Turing học viên đã cài đặt, từ đó chỉ ra quan hệ giữa máy Turing và độ phức tạp của thuật toán
1.1 Giới thiệu chung
Máy Turing là một mô hình thiết bị xử lý kí tự, tuy đơn giản, nhưng có thể thực hiện tất cả các thuật toán máy tính Các máy Turing được Alan Turing trình bày năm 1936 Các máy Turing không dành cho việc trực tiếp tạo ra các máy tính thực tế mà dành cho các thí nghiệm tưởng tượng để tìm hiểu về giới hạn của việc tính toán trên máy móc Việc nghiên cứu tính chất máy Turing cho nhiều kiến thức quan trọng trong lĩnh vực khoa học máy tính
và lý thuyết độ phức tạp thuật toán [2]
Trong luận đề Church-Turing đã khẳng định mọi hàm toán học tính được đều có thể dùng máy Turing để tính toán do đó có phép định nghĩa về các khái niệm về sự tính được của hàm hoặc thuật toán
Máy Turing có nhiều dạng đồng khả năng, tức là có nhiều mô hình và định nghĩa cho máy Turing nhưng chúng đều tương đương nhau Về cơ bản
mô hình máy Turing gồm 3 phần chính sau:
- Một bộ điều khiển hữu hạn
- Một băng chia thành các ô
- Một đầu đọc-ghi, mỗi lần đọc có thể duyệt qua một ô trên băng để đọc hay viết ký hiệu.[2]
Trang 11Bộ điều khiển có số trạng thái hữu hạn trong đó có trạng thái ban đầu và trạng thái kết thúc Như vậy khi máy Turing bắt đầu hoạt động sẽ nhận trạng thái đầu tiên là trạng thái ban đầu, máy chỉ dừng khi đạt trạng thái kết thúc Trên băng mỗi ô có thể giữ một ký hiệu hợp lệ (ký hiệu được phép ghi trên băng) khởi đầu xem như n ô bên trái (n 0) giữ chuỗi nhập (input), các ô còn lại là các ký tự trắng (ký tự trắng là ký tự đặc biệt nhưng không thuộc chuỗi nhập), phần còn lại của băng được coi là vô hạn
Đầu đọc ghi có thể di chuyển sang trái, phải hoặc đứng yên tùy vào trạng thái hiện tại và ký tự nhận được Đầu đọc ghi có thể nhận dạng kí tự hiện hành và viết đè một ký tự khác vào ô đó để thay ký tự cũ
Hình 1.1 Mô hình máy Turing 1.2 Cấu trúc máy Turing
Về mặt toán học máy Turing có thể được định nghĩa như sau:
Định nghĩa máy Turing:[7]
Máy Turing là một hệ thống M ( , , , ,Q q B F0, , ), trong đó:
Q là tập hữu hạn các trạng thái
là bộ ký hiệu nhập
là tập hữu hạn các kí tự được phép viết trên băng
B là ký hiệu thuộc dùng chỉ khoảng trắng trên băng (Blank)
Trang 12Trong đó:
S: là trạng thái hiện hành của máy Turing
C: là ký tự tại ô mà con trỏ đang trỏ
R: là kí tự sẽ điền thay vào vị trị của C, nếu R = _ tức là giữ nguyên kí tự C T: là hướng dịch chuyển của con trỏ bao gồm L: dịch trái
Trang 13Trạng thái hiện hành của máy Turing là 1, con trỏ máy đang chỉ vào ô chứa kí tự “a”, máy Turing sẽ điền kí tự “b” thay thế vào ô đó Con trỏ máy sau đó chuyển dịch sang phải 1 ô, trạng thái máy chuyển thành 2
Để cải tiến cách soạn thảo học viên cài đặt máy Turing nhận các câu lệnh trong đó thay thế các thành phần không thay đổi trong lệnh máy thành dấu gạch dưới Và có thể dùng câu lệnh gộp khi 1 trạng thái gặp nhiều kí tự khác nhau nhưng có cùng cách xử lý như nhau
Ví dụ:
Lệnh 1 _ _ _ _ sẽ hoạt động như sau:
Nếu máy đang ở trạng thái 1
Ô nhớ đang được con trỏ máy trỏ vào chứa bất cứ ký tự nào;
Giữ nguyên ký tự đó;
Con trỏ không dịch chuyển;
Trạng thái sau khi thực hiện lệnh không thay đổi là trạng thái 1
Ví dụ: câu lệnh gộp
1 {a,b,c} _ R _ sẽ hoạt động như sau:
Trạng thái hiện hành của máy Turing là trạng thái “1”
Đầu đọc ghi trỏ tới một trong các kí tự “a”, “b”, “c” sẽ giữ nguyên kí tự đó Đầu đọc ghi dịch chuyển sang phải 1 ô
Trạng thái máy Turing giữ nguyên là trạng thái “1”
Ví dụ: Xét tính chẵn lẻ của một số
- Tư tưởng thuật toán: để xét một số là chẵn hay lẻ chỉ cần chia lấy phần dư cho 2, nếu kết quả là 1 suy ra số đó là số lẻ, còn kết quả là 0 số đó là số chẵn Hoặc nếu biểu diễn số cần xét là một dãy các chữ số: X = X X X1 2 n1Xn, nếu
Trang 14chữ số cuối cùng X n {0, 2, 4, 6,8} thì số cần xét X là số chẵn, nếu chữ số cuối cùng X n {1,3,5,7,9} thì số cần xét X là số lẻ
Mã chương trình máy Turing:
Kết quả của chương trình:
Mô phỏng với số đầu vào là 33
Trang 15Vậy với thuật toán trên máy Turing trải qua 6 bước chuyển, số ô sử dụng
là 2
So sánh cách soạn thảo viết rõ từng lệnh máy với cách sử dụng những
kí hiệu mà học viên cài đặt:
Bảng 1.1 So sánh câu lệnh giữa cách viết thông thường
1.3 Hoạt động của máy Turing
Máy Turing hoạt động theo cơ chế như sau:[5]
- Đầu đọc ghi đọc một kí tự trên ô của băng, phụ thuộc vào trạng thái bên trong mà đầu đọc ghi ghi một kí tự hợp lệ vào ô đó (kí tự thuộc tập )
- Đầu đọc ghi dịch chuyển sang trái, sang phải hoặc đứng yên tại chỗ
- Trạng thái bên trong được thay đổi tùy vào kí tự được đọc và trạng thái hiện hành
Trang 16- Máy Turing bắt đầu từ trạng thái ban đầu và dừng khi đạt trạng thái kết thúc
Máy Turing được mô tả trong luận văn của học viên hoạt động theo đúng cơ chế trên, cụ thể trong chương trình học viên quy ước trạng thái bắt đầu của máy Turing là trạng thái “1”, trạng thái kết thúc là trạng thái “0” Vậy một chương trình viết bởi các câu lệnh để mô tả thuật toán sẽ dừng lại khi gặp câu lệnh dạng (S C R T 0) Các thành phần của câu lệnh đã được học viên trình bày ở phần 1.2
1.4 Trạng thái và sơ đồ trạng thái của máy Turing[2]
Một hình thái của máy Turing M được cho bởi α1 q α2, trong đó q là trạng thái hiện hành của M; α1α2 ∈ Γ* là nội dung của băng tính từ đầu băng
cho tới ký hiệu khác Blank bên phải nhất của băng Giả sử Q và Γ rời nhau: đầu đọc đang đọc ký hiệu bên trái nhất của α2 hoặc nếu α2 = ε thì đầu đọc đọc Blank
Hàm chuyển
Ta định nghĩa một phép chuyển trạng thái của TM như sau:
Đặt X1X2 Xi-1q Xi Xn là một hình thái của máy Turing
+ Giả sử δ (q, Xi) = (p, Y, L), trong đó:
- Nếu i - 1 = n thì Xi là B
- Nếu i =1 thì không có ID kế tiếp, nghĩa là đầu đọc không được phép vượt qua cận trái của băng
- Nếu i > 1 ta viết:
Trang 17X1X2 Xi-1q Xi Xn M X1X2 Xi-2p Xi-1Y Xi+1 Xn
+ Tương tự δ(q, Xi) = (p, Y, R) thì ta viết:
X1X2 Xi-1q Xi Xn M X1X2 Xi-1Yp Xi+1 Xn
+ Tương tự δ(q, Xi) = (p, Y, ) thì ta viết:
X1X2 Xi-1q Xi Xn M X1X2 Xi-1pY Xi+1 Xn
Chú ý rằng nếu i - 1 = n thì chuỗi Xi Xn là rỗng và vế phải dài hơn vế trái, nghĩa là TM M mở rộng chuỗi ký hiệu trên băng
Nếu hai hình thái máy được quan hệ nhau bởi M thì ta nói hình thái
thứ hai là kết quả của hình thái thứ nhất bằng một lần chuyển, một bước áp dụng hàm chuyển (hoặc nói hình thái thứ hai thu được từ hình thái thứ nhất bằng một lần chuyển) Nếu một hình thái thu được từ hình thái khác bằng một
số lần chuyển (có thể bằng 0) thì ta ký hiệu quan hệ là M* Ta cũng có thể
bỏ đi ký hiệu M trong cách viết các quan hệ trên nếu không có nhầm lẫn Ngôn ngữ được chấp nhận bởi TM
Ký hiệu L(M): tập hợp các chuỗi trong Γ* là nguyên nhân đưa TM M đi vào trạng thái kết thúc khi đã thực hiện việc thay thế từ bên trái các ký hiệu trên băng của M với trạng thái bắt đầu q0 Một cách hình thức, ta định nghĩa tập hợp ngôn ngữ được chấp nhận bởi TM M (Q, ∑, Γ, δ, q0, B, F) là tập:
L(M) = { w | w ∈ Γ* và q0 w M* α1 p α2 với p ∈ F còn α1α2 ∈ Γ*}
Trang 18Cho TM nhận diện một ngôn ngữ L là cho lần lượt các từ của L vào TM xem TM có chấp nhận từ đó không TM sẽ dừng và đi vào một trong những trạng thái kết thúc ∈ F (không có phép chuyển kế tiếp) khi từ được chấp
nhận, nhưng nếu TM không chấp nhận một từ nào đó thì TM có thể ngừng ở một trạng thái F hoặc cũng có thể nó chạy mãi mà không dừng lại
Ví dụ: Thiết kế TM chấp nhận ngôn ngữ L = { 0n1n | n ≥ 1}
Cách 1: Thiết kế bằng định nghĩa của máy Turing:
- Tư tưởng thuật toán:
+ Khởi đầu TM chứa 0n1n bên trái nhất trên băng sau đó là vô hạn khoảng trống Blank TM lặp lại quá trình sau:
+ M thay 0 bên trái nhất bằng X rồi chuyển sang phải tới 1 trái nhất, TM thay 1 này bằng Y rồi dịch chuyển về bên trái cho tới khi gặp X phải nhất nó chuyển sang phải một ô (tới 0 trái nhất) rồi tiếp tục lặp một chu trình mới + Nếu trong khi dịch chuyển sang phải để tìm 1 mà TM gặp Blank thì
TM dừng và không chấp nhận input Tương tự, khi TM đã thay hết 0 bằng X
và kiểm tra còn 1 trên băng thì TM cũng dừng và không chấp nhận input + TM chấp nhận input nếu như cũng không còn ký hiệu 1 nào nữa trên băng
- Định nghĩa máy Turing:
Đặt TM M (Q, ∑, Γ, δ, q0, B, F) với các thành phần:
Q = {q0, q1, q2, q3, q4}; ∑= {0, 1}; Γ = {0, 1, X, Y, B} và F = {q4}
Ta có thể hình dung mỗi trạng thái là một câu lệnh hoặc một nhóm các câu lệnh trong chương trình Trạng thái q0 là trạng thái khởi đầu và nó làm
Trang 19cho ký hiệu 0 bên trái nhất thay bằng X Trạng thái q1 được dùng để tiến sang phải bỏ qua các số 0 và Y để tìm 1 bên trái nhất Nếu M tìm thấy 1 nó thay 1 bằng Y rồi đi vào trạng thái q2 Trạng thái q2 đưa M tiến sang trái cho tới X đầu tiên và đi vào trạng thái q0, dịch chuyển sang phải để tới 0 bên trái nhất và tiếp tục một chu trình mới Khi M tiến sang phải trong trạng thái q1, nếu B hoặc X được tìm thấy trước 1 thì input bị loại bỏ (không chấp nhận) vì có chứa nhiều ký hiệu 0 hơn 1 hoặc input không có dạng 0*1*
Trạng thái q0 còn có vai trò khác Nếu trạng thái q2 tìm thấy X bên phải nhất và ngay sau đó là Y thì các số 0 đã được xét hết, do đó ở trạng thái bắt đầu một chu trình mới q0 không tìm thấy ký hiệu 0 nào để thay thành X mà chỉ gặp Y thì TM đi vào trạng thái q3 duyệt qua các Y để kiểm tra có hay không có ký hiệu 1 còn lại Nếu theo ngay sau các Y là B, nghĩa là trên băng nhập không còn ký hiệu 1 nào nữa thì TM sẽ đi vào q4 (trạng thái kết thúc) để chấp nhận input Ngược lại input bị loại bỏ
Hàm chuyển δ được cho trong bảng sau:
Bảng 1.2 Trạng thái máy Turing đoán nhận ngôn ngữ L = {0 n 1 n | n ≥ 1}
Trang 20Ví dụ:
+ Các phép chuyển hình thái của TM M trên input 0011:
q00011 Xq1011 X0q111 X q20Y1 q2X0Y1 X q00Y1 XXq1Y1
XXY q11 XX q2YY X q2XYY XX q0YY XXYq3Y XXYYq3
XXYYq4Với chuỗi input 0011 máy Turing đạt được trạng thái q4 thuộc tập trạng thái dừng, nên máy Turing trên đoán nhận được xâu 0011
+ Các phép chuyển hình thái của TM M trên input 0001
q00001 Xq1001 X0q101 X 00q1 1 X0q20Y X q200Y
q2X00Y Xq000Y XX q10Y X q2XYY XX 0q1Y XX0Yq1
Với chuỗi input 0001 TM M không đạt được trạng thái kết thúc nên không đoán nhận được xâu 0001 hay xâu input 0001 không thuộc ngôn ngữ L
= { 0n1n | n ≥ 1}
Cách 2: Thiết kế bằng lệnh máy Turing do học viên cài đặt:
- Tư tưởng thuật toán:
Về cơ bản thuật toán giống với cách 1 Học viên thêm vào kết thúc của các xâu input kết luận máy TM M có đoán nhận được xâu hay không ở output
Trang 218 # K N 0 // đạt trạng thái dừng không đoán nhận được
- Trong đoạn mã lệnh trên ta có:
Trang 22Command: 2 0 _ R _ # X011# (4)
Command: 2 1 Y L 3 # X0Y1# (4) Command: 3 0 _ L 3 # X0Y1# (4)
Command: 3 X _ R 1 # X0Y1# (4) Command: 1 0 X R 2 # XXY1# (4) Command: 2 Y _ R 2 # XXY1# (4) Command: 2 1 Y L 3 # XXYY# (4) Command: 3 Y _ L 3 # XXYY# (4) Command: 3 X _ R 1 # XXYY # (4) Command: 1 Y _ R 4 # XXYY # (4) Command: 4 Y _ R 4 # XXYY # (4) Command: 4 # _ N 5 # XXYY # (4) Command: 5 # = R 6 # XXYY = # (5) Command: 6 # D N 0 # XXYY = D# (6) Final output: #XXYY=D# (6)
Timer = 15
Vậy với input 0011 được máy Turing đoán nhận Thời gian hoàn thành là 15 bước chuyển
Không gian bộ nhớ tối đa là 6 ô
+ Chương trình chạy với input 010
Input: #010# (3)
Command: 1 0 X R 2 #X10# (3)
Command: 2 1 Y L 3 #XY0# (3)
Trang 23Vậy máy TM M không đoán nhận được input 010
Bộ nhớ tối đa cần dung là 5 ô
Chương trình thực hiện sau 8 bước chuyển máy
1.5 Máy Turing và định nghĩa thuật toán
1.5.1 Độ phức tạp thuật toán
a) Định nghĩa thuật toán[1]
Ta có thể định nghĩa (không chính thức) về thuật toán như sau:
Thuật toán là một dãy hữu hạn các bước, mỗi bước mô tả chính xác các phép toán, hoặc hành động cần thực hiện… để chuyển input thành output
b) Các đặc trưng của thuật toán
- Đầu vào (Input)
Đầu vào của thuật toán chính là các giá trị cần đưa vào khi thuật toán bắt đầu làm việc Các giá trị này cần được lấy từ các tập hợp giá trị cụ thể nào đó
- Đầu ra (Output)
Trang 24Mỗi thuật toán có một hoặc nhiều dữ liệu ra Đó là các dữ liệu có quan
hệ hoàn toàn xác định với các dữ liệu vào, và là kết quả của sự thực hiện thuật toán
- Tính xác định
Ở mỗi bước, các thao tác phải rõ ràng, không gây nên sự nhập nhằng Nói rõ hơn là trong cùng một điều kiện, hai bộ xử lí cùng thực hiện một thuật toán phải cho cùng một kết quả như nhau
- Tính khả thi
Tất cả các phép toán có mặt trong thuật toán phải đủ đơn giản Điều đó
có nghĩa là, các phép toán có thể được thực hiện trực tiếp (bằng giấy và bút)
Trang 25T1(n) + T2(n) = O(max(f(n),g(n)))
Ví dụ: Trong một chương trình có 3 bước thực hiện mà thời gian thực
hiện từng bước lần lượt là O(n2), O(n3) và O(nlog2n) thì thời gian thực hiện 2 bước đầu là O(max(n2, n3)) = O(n3) Thời gian thực hiện chương trình sẽ là O(max(n3, nlog2n)) = O(n3)
Một ứng dụng khác của quy tắc này là nếu g(n) ≤ f(n) với mọi n n0 thì O(f(n) + g(n)) cũng là O(f(n)) Chẳng hạn: O(n4 + n2) = O(n4) và O(n+log2n) = O(n)
* Quy tắc nhân: Nếu tương ứng với P1 và P2 là T1(n) = O(f(n)), T2(n) = O(g(n)) thì thời gian thực hiện P1 và P2lồng nhau sẽ là:
T1(n)T2(n) = O(f(n)g(n))
Ví dụ: Câu lệnh gán: x:=x+1 có thời gian thực hiện bằng c (hằng số) nên được đánh giá là O(1)
Câu lệnh for i:=1 to n do x:=x+1;
Có thời gian thực hiện O(n.1) = O(n)
Câu lệnh: for i:=1 to n do
for j:=1 to n do x:=x+1;
Có thời gian được đánh giá là O(n.n) = O(n2)
Cũng có thể thấy O(cf(n)) = O(f(n)) Ví dụ O(n2/2) = O(n2)
Các vấn đề liên quan đến thuật toán
Thiết kế thuật toán
Có một số kỹ thuật thiết kế thuật toán chung như:
- Chia để trị (divide and conque)
Trang 26- Phương pháp tham lam (greedy method)
- Phương pháp quy hoạch động (dynamic programing)
Nắm được các kỹ thuật thiết kế thuật toán là rất quan trọng giúp tìm ra các thuật toán mới cho các bài toán mới
Lớp P, NP và mối quan hệ giữa lớp P và lớp NP.[3],[7],[8]
- Lớp P
* Định nghĩa:
Lớp P là lớp những bài toán giải quyết được bằng máy tính Turing tất định trong thời gian đa thức
* Ví dụ: Thuật toán Ơclide tìm UCLN của hai số là thuật toán giải được
trong thời gian đa thức Do đó bài toán tìm UCLN của hai số m và n thuộc lớp P
- Lớp NP
* Định nghĩa:
Lớp NP là lớp các bài toán có thể giải được bằng máy Turing không tất định trong khoảng thời gian đa thức
* Ví dụ: Bài toán chu trình Hamilton
- Instance: Cho đồ thị vô hướng G = (V,E)
- Question: Hỏi đồ thị vô hướng G = (V,E) có chu trình Hamilton hay không?
- Mối quan hệ giữa lớp P và lớp NP
Trang 27Hình 1.2 Mối quan hệ giữa lớp P và NP
Bài toán lớp NPC
Phép dẫn với thời gian đa thức
* Định nghĩa:
Cho n 1 và 2 là hai bài toán quyết định
y là lớp các Instance ứng với YES
y là lớp các Instance ứng với NO
Một cách biến đổi f biến mỗi Instance của 1 thành Instance của 2 được gọi là phép dẫn thời gian đa thức nếu điều đó thoả mãn:
- Phép dẫn f thực hiện được trong thời gian đa thức bởi máy tính Turing
- Mỗi dữ kiện thuộc 1(y) thành dữ kiện thuộc 2(y).
- Mỗi dữ kiện thuộc 1(n) thành dữ kiện thuộc 2(n).
NP
P
Trang 28Hình 1.3 Minh hoạ một phép dẫn bài toán 1 thành 2
trong thời gian đa thức
Bài toán lớp NPC.[9]
* Định nghĩa: Một bài toán thuộc lớp NP mà mọi bài toán thuộc lớp NP
khác đều dẫn được về nó với thời gian đa thức được gọi là bài toán NPC
* Tính chất: một bài toán là NPC nếu thoả mãn:
1 NP
2 Với ’ NP thì ’ dẫn được về với thời gian đa thức
Như vậy để chứng minh một bài toán là NPC ta cần chứng minh hai điều:
1 Bài toán đó phải thuộc lớp NP
2 Mọi bài toán thuộc lớp NP đều dẫn được về bài toán đó với thời gian
đa thức
Mối quan hệ giữa các bài toán lớp P, NP và NPC
Mối quan hệ giữa P, NP và NPC được biểu diễn như hình sau:
Trang 29Hình 1.4 Mối quan hệ giữa lớp P, NP và NPC
1.5.2 Ứng dụng máy Turing để đo độ phức tạp thuật toán
Với phần sơ lược về thuật toán ở trên ta có thể thấy với một thuật toán tính ưu việt được thể hiện ở hai thông số đó là thời gian xử lí (số bước hay còn gọi là số xung làm việc của máy tính) và không gian bộ nhớ (là số ô nhớ phải sử dụng trong quá trình đưa input thành output)
Khi Alan Turing phát biểu máy Turing thì ông đã chứng minh được mọi thuật toán đều có thể mô tả được bằng máy Turing, chính vì thế việc dùng máy Turing làm thước đo độ phức tạp của thuật toán là điều có thể làm được Hiện nay trên thế giới có nhiều cách để đánh giá độ phức tạp của thuật toán nhưng xét cho cùng thì chưa có thước đo chuẩn nào
Máy Turing, là một máy ảo, hoàn toàn có thể trở thành một thước đo chính xác vì máy không phụ thuộc vào cấu hình phần cứng, máy chỉ dựa vào
số bước chuyển đầu đọc và số lượng ô nhớ cần dùng
Mặt khác vì mọi câu lệnh đều có thể chuyển về hàm chuyển của máy Turing nên hoàn toàn có thể đánh giá chính xác cách làm việc của một thuật toán
Hơn nữa phát hiện của Turing rằng "phần mềm luôn có thể thay cho phần cứng" là then chốt của "ảo hóa" - công nghệ nền tảng của làn sóng hợp nhất đang định hình lại hệ thống IT của các công ty lớn Khi chi phí cho năng lực tính toán và dung lượng lưu trữ tiếp tục đà rơi tự do từ chục năm nay, thì ngày càng có thể biến càng nhiều phần cứng thành chương trình phần mềm - dùng một máy tính thật mạnh để chạy nhiều máy ảo
Tất cả thiết bị phần cứng gắn vào các trung tâm dữ liệu doanh nghiệp - không chỉ server mà còn cả các ổ đĩa lưu trữ, thiết bị cân bằng tải, tường lửa, chuyển mạch và thậm chí cả cáp nối - thực chất là để thực hiện các lệnh Ảo hóa đơn giản là biến các lệnh phần cứng thành mã lệnh chương trình (phần mềm) và loại bỏ cỗ máy vật lý Điều này không chỉ tiết kiệm hàng đống tiền
Trang 30mà còn giúp hiện thực việc tự động hóa những qui trình CNTT thủ công trước đây Một khi hạ tầng CNTT biến thành phần mềm, nó có thể được lập trình,
dễ dàng và từ xa Như thường lệ, chương trình phần mềm thay thế nhân công
1.6 Kết luận
Trong chương này học viên đã trình bày những khái niệm cơ bản về máy Turing và thuật toán nhằm phát triển máy Turing thành công cụ đo độ phức tạp thuật toán Cụ thể như sau:
- Trình bày các khái niệm như định nghĩa máy Turing, sơ đồ trạng thái, hoạt động của máy Turing
- Trình bày các khái niệm như thuật toán, các tính chất của thuật toán và các vấn đề liên quan đến thuật toán
- Khái quát một số bài toán dạng P, NP, NPC
- Nêu mối liên hệ giữa thuật toán và máy Turing Từ đó đề cập đến vấn
đề “ảo hóa” các thiết bị phần cứng
Trang 31Chương 2 CÀI ĐẶT MÁY TURING NGUYÊN THỦY
VÀ MỘT SỐ CẢI TIẾN
Trong chương này học viên xin trình bày chương trình cài đặt máy Turing nguyên thủy hay còn gọi là máy Turing đơn định một băng Để cải tiến tốc độc
xử lí của máy học viên đề xuất một số giải pháp cải tiến bộ nhớ máy.[5]
2.1 Cài đặt Máy Turing
Để mô phỏng máy Turing học viên đã sử dụng ngôn ngữ lập trình C++ Sau đây học viên xin giới thiệu các thành phần chính của chương trình
- Hàm chính để khởi động máy Turing:
main(){
cout << " T H E T U R I N G M A C H I N E "; Run();
Sau khi hàm Run () được gọi trong chương trình, chương trình dừng lại
để người dùng nhập đường dẫn đến tệp chứa lệnh máy hoặc dùng tệp mặc định Prog.tr
Trang 32Các hàm thành phần:
Hàm Test (): được dùng để kiểm tra sự đúng đắn của chương trình Ngoài ra hàm Test () còn điều khiển một số tác năng khác của máy Turing như: hiển thị các bước trung gian của thuật giải, tín hiệu nhập dữ liệu từ bàn phím, mở Help để xem chỉ dẫn Một số chỉ dẫn điển khiển chương trình như: + Dấu chấm “.” để dừng chương trình đang chạy (ngắt chương trình bắt buộc) + Dấu hỏi chấm “?” đặt trước input để chạy chương trình máy Turing…
void Test(const char * fn){
}
}
Trang 33Hàm GetComm () có tác dụng lấy từng câu lệnh trong tệp mã lệnh (tệp mặc định là tệp Prog.tr) sau đó hàm CorrectTest () kiểm tra tính đúng của từng câu lệnh:
void GetComm(char * s, const char * msg = ""){
Trang 34Một số hàm khác để chuẩn hóa câu lệnh:
+ Hàm Correct () loại bỏ các phần chú thích trong đoạn mã lệnh máy Turing
char Correct(char * s, int d = 0){
+ Hàm ReadLine () đọc từng dòng trong tệp chứa lệnh Prog.tr hoặc tệp
mã lệnh do người dùng tạo ra
Trang 35int GetNum(char * s, int & i){
int v = 0;
for (; !Num(s[i]); ++i);
for (; Num(s[i]); ++i) v = v*10+Toint(s[i]);
i;
return v;
}
+ Hàm Space () dùng để bỏ qua các dấu cách trống vô nghĩa
inline void Space(char * s, int & i){
while(s[i] == SPACE) ++i;
}
+ Hàm GetChar () có tác dụng lấy các lí tự có nghĩa
inline char GetChar(char * s, int & i){
Space(s,i);
return s[i];
}
// Nhan cac chu cai trong day { }
inline void XuLiSet(const char *s, int i, int state, Com & cm){
for (i++; s[i] != '}' ; ++i)
if (GOODCHAR(s[i]) && s[i] != ',')
p[state][s[i]] = cm;
}
Trang 36Các hàm trên sau khi hoạt động sẽ loại bỏ các các thành phần không cần thiết như các dấu cách, phần chú thích trong mã lệnh ở tệp Prog.tr hoặc tệp người dùng chỉ định để đơn giản hóa các câu lệnh khi chạy trên máy Turing
2.1.1 Giao diện chương trình
- Chương trình máy Turing bắt đầu hoạt động sẽ được hiển thị như sau:
Hình 2.1 Giao diện máy Turing
Khi máy Turing bắt đầu hoạt động sẽ đưa ra gợi ý về các điều khiển của chương trình