Tải bản đầy đủ (.doc) (11 trang)

Thuật toán biểu diển đồ thị theo Forward Star

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (126.54 KB, 11 trang )

TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN
CHƯƠNG TRÌNH ĐÀO TẠC THẠC SĨ CNTT QUA MẠNG
LẬP TRÌNH SYMBOLIC TRONG MAPLE
Bộ môn: Lập trình Symbolic và ứng dụng
Giáo viên hướng dẫn: PGS.TS. Đỗ Văn Nhơn
Sinh viên: Trần Hoài Phong
MSSV: CH1101027
Niên khóa 2011 - 2013
Mục lục
Lời mở đầu
Có ba thành phần có thể được lập trình: lôgic – đây là quá trình mô tả ở cấp độ
cao của việc làm thế nào để có thể giải quyết một vấn đề, điều khiển – làm sao để thao
tác với máy tính ở cấp độ thấp để có được giải pháp, và trừu tượng – xác định các đối
tượng phức tạp bằng các thuộc tính có liên quan để giải quyết một vấn đề. Khó khăn
thực sự trong việc giải quyết một vấn đề sẽ có liên quan đến hai phần: lôgic và trừu
tượng. Với nhu cầu hiện nay, các phần mềm đã ngày càng phát triển và trở nên lớn
hơn. Trí tuệ nhân tạo là một lĩnh vực như vậy với các ứng dụng được đặc trưng bằng
cách sử dụng các tính toán hình thức hơn là tính toán số học. Loại ứng dụng này đôi
khi đòi hỏi phải linh hoạt hơn các lĩnh vực ứng dụng khác.
Các ngôn ngữ lập trình Symbolic hỗ trợ lập trình ở cấp độ cao bằng cách nhấn
mạnh vào lôgic và trừu tượng: mọi thao tác phức tạp đều được ẩn trong ngôn ngữ do
đó việc lập trình rất biểu cảm, ngắn ngọn, dễ hiểu và do đó có thể được duy trì dễ dàng.
Và đặc biệt trong các lĩnh vực liên quan đến tính toán đến các phương trình đại số và vi
phân… thì maple đã nổi lên thành một công cụ phổ biến vô cùng hữu ích cho các nhà
lập trình cấp cao.
Trong bài tiểu luận này em sẽ đưa ra một số kiến thức tổng quát về lập trình
symbolic nói chung cũng như maple nói riêng để phần nào biết được một cách lập trình
khác biệt so với những gì thông thường chúng ta lập trình đồng thời đưa ra một ví dụ
minh hoạ dùng trực tiếp maple để thực hiện các tính toán hình thức. Vì thời gian và
kiến thức có hạn nên bài tiểu luận vẫn còn nhiều hạn chế rất mong được sự đóng góp ý
kiến từ thầy.


Niên khóa 2011 - 2013
2
Cuối cùng em xin cám ơn thầy đã rất nhiệt tình hướng dẫn trong quá trình giảng
dạy. Thầy đã cung cấp cho em nhiều kiến thức quý giá đặc biệt trong lĩnh vực tính toán
hình thức cũng như lập trình trong lĩnh vực trí tuệ nhân tạo qua đó giúp em có thể
nghiên cứu sâu hơn trong lĩnh vực này đồng thời giải quyết những vấn đề mà nếu dùng
các ngôn ngữ lập trình thông thường là rất phức tạp.
1. Lập trình symbolic
1.1. Khái niệm
Lập trình symbolic là ngôn ngữ lập trình mà trong đó các chương trình có thể tự
xử lý, hoặc lập trình với các dữ liệu cấp cao. Không chỉ gồm một chuỗi kí tự hoặc văn
bản mà là các dữ liệu thực sự có cấu trúc trong đó chương trình có thể thao tác được.
Nói chung, trong ngôn ngữ lập trình symbolic, các cấu trúc dữ liệu phức tạp có
thể dễ dàng tạo ra – người dùng có thể dễ dàng tạo ra nó đơn giản chỉ bằng cách viết
trực tiếp chúng và sau đó có thể mở rộng nó bằng một vài phép toán đơn giản. Nhờ lập
trình symbolic mà thay vì được tạo một chương trình trong ngôn ngữ bình thường đòi
hỏi những xử lý rất phức tạp thì có thể dễ dàng được khai báo trong symbolic.
Thực tế, sự hấp dẫn của các ngôn ngữ lập trình symbolic phần lớn đến từ sự dễ
dàng trong việc tạo và thao tác trên các dữ liệu có cấu trúc phức tạp.
1.2. So sánh lập trình symbolic với lập trình hàm và lập trình lô gíc
Lập trình hàm là lập trình bằng cách xác định các hàm (ví dụ nghịch đảo của X
là 1 chia cho X) hơn là nói với máy tính cần phải làm cái gì (đưa 1 vào trong bộ nhớ,
chia nó cho X, lưu kết quả lại). Lập trình hàm thường xuyên có rất nhiều hàm ngắn
được định nghĩa hơn là một chuỗi mã dài. Tiêu biểu là LISP.
Lập trình logic là lập trình điều khiển thông qua một mô hình lý luận nguyên
nhân kết quả (ví dụ tôi có thể kết luận Y là đối xừng của X nếu tôi có thể làm điều này
…). Tiêu biểu là prolog.
2. Maple
Niên khóa 2011 - 2013
3

Maple là một ứng dụng giúp chúng ta có thể giải quyết các phương trình đại số
và vi phân. Maple có khả năng thực hiện các phép toán dưới dạng hình thức và do đó
nó có thể dùng để phân tích các giải pháp cho các phương trình đại số và vi phân. Với
khả năng tính đạo hàm, tích phân và các tính toán đại số cũng như các biểu thức toán
học dưới dạng hình thức đây là một giải pháp vô cùng mạnh mẽ và giúp chúng ta giải
quyết được rất nhiều vấn đề phức tạp mà nếu chúng ta dùng một ngôn ngữ lập trình
bình thường để giải thì sẽ vô cùng kì công.
Ngoài ra maple còn cung cấp rất nhiều tài liệu tham khảo hữu ích trong toán
học. Ví dụ trong trường hợp người dùng quên đạo hàm của sin là cosin thì có thể dễ
dàng dùng Maple để nhanh chóng tìm kiếm thông tin này. Maple có thể thay thế rất
nhiều công thức toán học qua đó có thể giúp chúng ta giải quyết rất nhiều vấn đề về
khoa học kỹ thuật.
3. Ứng dụng trong maple
3.1. Phân tích yêu cầu
Thuật toán Dijkstra được hình hành bởi Edsger Dijkstra vào năm 1956 và được
công bố vào năm 1959. Đây là một thuật toán để giải quyết vấn đề tìm đường đi ngắn
nhất cho một đồ thị mà không có cạnh nào có trọng số âm. Thuật toán này thường dùng
cho việc định tuyến và như là một thủ tục con trong các thuật toán về đồ thị khác.
Cho trước một đỉnh gốc trong một đồ thị, thuật toán sẽ tìm đường đi với chi phí
nhỏ nhất (tức là đường đi ngắn nhất) giữa đỉnh nguồn này với tất cả các đỉnh. Nó cũng
có thể được dùng để tìm kiếm chi phí của đường đi ngắn nhất từ một đỉnh tới một đỉnh
khác bằng cách dừng thuật toán khi đường đi ngắn nhất tới đỉnh đích đã được xác định.
Hiệu suất hoạt động của một thuật toán về đồ thị phụ thuộc vào: thuật toán và
cấu trúc dữ liệu. Để biểu diễn một đồ thị chúng ta cần phải lưu trữ hai thông tin: một là
các đỉnh các cạnh, hai là các dữ liệu về chi phí, cung cầu, có liên quan đến các đỉnh
và các cạnh. Ở đây ta dùng cấu trúc Forward và Reverse Star. Cấu trúc này sẽ được đề
cập trong phần sau.
Niên khóa 2011 - 2013
4
3.2. Cấu trúc dữ liệu

1.1.1. Cấu trúc đầu vào
Một đồ thị sẽ được xác định thông qua một danh sách gồm các danh sách con
với một dãy các con số dùng để xác định đồ thị
1) Danh sách con đầu tiên chứa số đỉnh trong đồ thị, số cạnh và đỉnh gốc.
2) Các danh sách con còn lại xác định các cạnh trong đồ thị. Mỗi danh sách
chứa đỉnh bắt đầu, kết thúc và chi phí của cạnh.
Ví dụ:
dothi := [
[4, 6, 1], // 4 đỉnh, 6 cạnh, đỉnh gốc là 1
[1, 2, 1], // cạnh từ 1 đến 2 với chi phí là 1
[1, 3, 3],
[2, 3, 2],
[3, 2, 4],
[2, 4, 5],
[3, 4, 9]
];
1.1.2. Biểu diễn theo kiểu Forward Star
Một đồ thị sẽ được xác định thông qua một danh sách gồm các danh sách con
với một dãy các con số dùng để xác định được một đồ thị. Đồ thị sẽ lưu trữ một danh
sách các đỉnh liền kề nhau theo dạng mảng qua đó cung cấp cho chúng ta một cách để
có thể xác định hiệu quả tập hợp các cạnh đi ra từ bất kỳ đỉnh nào trong đồ thị.
Chúng ta thực hiện sắp xếp các cạnh lại theo thứ tự sau: đầu tiên là các cạnh từ
đỉnh 1 và sau đó là các cạnh từ đỉnh 2 và cứ tiếp tục như vậy. Với mỗi cạnh chúng ta
Niên khóa 2011 - 2013
5
đánh một số theo thứ tự. Sau đó lần lượt lưu trữ các thông tin về mỗi cạnh trong danh
sách cạnh. Chúng ta lưu trữ đỉnh gốc, đỉnh kết thúc, chi phí trong ba mảng khác nhau.
Ngoài ra còn lưu 1 con trỏ cho mỗi đỉnh i, được kí hiệu là point(i) chỉ ra cạnh
nhỏ nhất trong danh sách cạnh mà xuất phát từ đỉnh i, nếu đỉnh i ko có cạnh nào đi ra
thì point(i) bằng với point(i+1). Vì vậy tất cả các cạnh đi ra từ đỉnh i tại các vị trí từ

point(i) đến point(i+1)-1.
Ví dụ:
Từ dothi ở trên ta tạo ra các mảng như sau
FS_tail = [1 1 2 2 3 3];
FS_head = [2 3 3 4 2 4];
FS_cost = [1 3 2 5 4 9];
FS_point = [1 3 5 7 7];
Ba mảng trên có thể được hiểu như sau phần tử đầu là cạnh từ đỉnh 1 đến đỉnh 3
với chi phí là 1, phần tử 2 là từ cạnh 1 đến cạnh 3 với chi phí là 3 và tương tự như vậy
với các phần tử sau.
point(1) = 1, point(2) = 3 tức là đỉnh 1 có cạnh 1 và 2 đi ra, đỉnh 2 có cạnh 3 và
cạnh 4,
1.1.3. Biểu diễn theo kiểu Reverse Star
Giúp xác định tập hợp các cạnh đi vào bấy kì đỉnh nào. Tương tự như Forward
Star ta cũng được một tập hợp các mảng nhưng thứ tự như sau:
Ví dụ:
FS_tail = [1 31 2 2 3];
FS_head = [2 2 3 3 4 4];
FS_cost = [1 4 3 2 5 9];
FS_rpoint = [1 1 3 5 7];
-> Thay vì lưu các cạnh đi ra thì ta lưu các cạnh đi vào.
Niên khóa 2011 - 2013
6
Tuy nhiên thay vì lưu lại tất cả các mãng tail, head, cost lặp lại như trên từ đó
làm hao tốn tài nguyên và bộ nhớ, ta chỉ cần lưu lại số cạnh và có thể dùng các thông
tin tương tự từ các mảng đã lưu trong Forward Star bằng cách lưu các con số cạnh
trong một mãng gọi là trace.
FS_Trace = [1 5 2 3 4 6]; trong đó cạnh 1 trong kiểu reverse star sẽ tương ứng
với cạnh 1 trong forward star, cạnh 2 trong reverse star sẽ tương ứng với cạnh 5 trong
forward star v.v

3.3. Thuật giải
1.1.4. Thuật toán biểu diển đồ thị theo Forward Star
- Bước 1:
Với mọi cạnh u, ta lần lượt gán đỉnh xuất phát, đỉnh kết thúc, chi phí vào ba
mảng raw_tail, raw_head, raw_cost
- Bước 2:
Với mọi đỉnh v ta lặp tất cả các cạnh u xem cạnh nào có đỉnh xuất phát từ v
Nếu tìm thấy ta lưu cách thông tin trong raw_tail, raw_head, raw_cost vào
FS_tail, FS_head, FS_cost đồng thời lưu lại thông tin thứ tự cạnh trong FS_point
1.1.5. Thuật toán dijkstra
- Bước 1:
Với mọi đỉnh v ∈ S, trọng số(v) := ∞
S := {}
i := Đỉnh gốc, trọng số(i)=0
- Bước 2:
Tìm tất cả đỉnh v có trọng số nhỏ nhất và chưa có trong s
Gán i = đỉnh vừa tìm được, trường hợp đầu tiên là đỉnh gốc
Niên khóa 2011 - 2013
7
Với mọi v S và kề với i∈
trọng số(v) := trọng số(i) + w(i)
- Bước 3:
Nếu chưa quá số đỉnh cho trong đồ thị
Lặp lại bước 2.
Nếu quá số đỉnh dừng thuật toán
3.4. Code dữ liệu
Vui lòng tham khảo file maple đính kèm.
3.5. Dữ liệu thử nghiệm
Ví dụ 1:
 Đầu vào:

dothi := [
[4, 6, 1], # 4 đỉnh, 6 cạnh, đỉnh gốc: 1
[1, 2, 1], # cạnh 1 - từ đỉnh 1 tới đỉnh 2, trọng số = 1
[1, 3, 3],[2, 3, 2],[3, 2, 4],[2, 4, 5],[3, 4, 9]
]:
ThuatToan_Dijkstras(dothi); # không vẽ đồ thị
 Đầu ra:
Đường đi ngắn nhất từ đỉnh nguồn 1:
Tới Đỉnh Trọng số Đỉnh trước
2 1 1
3 3 1
4 6 2
Ví dụ 2:
 Đầu vào:
dothi := [
Niên khóa 2011 - 2013
8
[9,36,1], # 9 đỉnh, 36 cạnh, đỉnh gốc 1
[1,2,5], # cạnh 1 - từ đỉnh 1 tới đỉnh 2, trọng số = 5
[1,3,9],[1,4,20],[1,5,4],[1,8,14],[1,9,15],
[2,1,5],[2,3,6],[3,1,9],[3,2,6],[3,4,15],
[3,5,10],[4,1,20],[4,3,15],[4,5,20],[4,6,7],
[4,7,12],[5,1,4],[5,3,10],[5,4,20],[5,6,3],
[5,7,5],[5,8,13],[5,9,6],[6,4,7],[6,5,3],
[7,4,12],[7,5,5],[7,8,7],[8,1,14],[8,5,13],
[8,7,7],[8,9,5],[9,1,15],[9,5,6],[9,8,5]
]:
ThuatToan_Dijkstras(net, true); //Vẽ đồ thị
 Đầu ra:
Đường đi ngắn nhất từ đỉnh nguồn 1:

Tới Đỉnh Trọng số Đỉnh trước
2 5 1
3 9 1
4 14 6
5 4 1
6 7 5
7 9 5
8 14 1
9 10 5
Niên khóa 2011 - 2013
9
4. Kết luận
Trong bài tiểu luận này em đã trình bày một số cái nhìn tổng quát về lập trình
symbolic nói chung cũng như maple nói riêng. Bài tiểu luận này chỉ đi vào một phần
tương đối nhỏ, tổng quát nhất. Đồng thời trong bài tiểu luận cũng có thêm một ví dụ về
cách ứng dụng maple để tìm được đường đi ngắn nhất bằng cách sử dụng thuật toán
Dijkstras. Qua ví dụ này ta có thể thấy được cách thức maple xử lý với các mảng, đồ
thị, qua đó phần nào thấy được cách làm thế nào để có thể giải quyết được một vấn đề
trong maple.
Các nghiên cứu này đã giúp cho em có được những kiến thức rất hữu ích. Qua
nó em có thể thấy được những hướng đi rất tốt mà sau này có thể áp dụng được sau
này. Các tri thức hiện tại của con người hiện giờ là rất khổng lồ. Nếu có thể áp dụng
được những gì vừa nghiên cứu được và mở rộng sâu hơn sẽ có thể tạo ra những sản
phẩm vô cùng hữu ích trong cuộc sống.
Hiện nay việc phát triển sáng tạo trong các phần mềm vẫn còn rất nhiều hạn
chế. Phần lớn đều dựa trên các ngôn ngữ lập trình thông thường. Do đó mọi người
thường gặp khó khăn khi yêu cầu phải làm ra các phần mềm đòi hỏi tính sáng tạo trong
giải quyết một vấn đề của bài toán. Do đó việc nghiên cứu một ngôn ngữ lập trình mới
như maple là rất cần thiết. Nó giúp chúng ta mở rộng thêm tư duy sáng tạo qua đó có
thể tạo ra những phần mềm để phục vụ tốt hơn cho cuộc sống cũng như cho xã hội.

Niên khóa 2011 - 2013
10
Mặc dù đã cố gắng nhưng do hạn chế về mặt thời gian cũng như kiến thức nên
phần tiểu luận không khỏi tránh được những khuyết điểm, sai sót. Rất mong được nhận
xét của thầy. Và cám ơn thầy đã dành thời gian xem phần tiểu luận của em.
Tài liệu tham khảo
[1] PGS.TS. ĐỖ VĂN NHƠN, Các slide trong môn Lập trình Symbolic và ứng
dụng
[2] Jay Pedersen , Dijkstra's Shortest Path Algorithm
/>[3] Dr. Masoud Yaghini , Network Flows Network Representations
/>sa=t&rct=j&q=Forward+Star+Reverse+Star+&source=web&cd=1&ved=0CC0
QFjAA&url=http%3A%2F%2Fwebpages.iust.ac.ir%2Fyaghini%2FCourses
%2FNetwork_891%2F01_3_Representations.pdf&ei=1eAFUd2SEKfriAewp4A
I&usg=AFQjCNGdZ_-
uOturDfWi8VnyHiyFTUiYJg&bvm=bv.41524429,d.aGc
Niên khóa 2011 - 2013
11

×