CHƢƠNG 1 : CƠ SỞ LÝ THUYẾT
3.1 Thiết lập bài toán
3.1.1 Viết chƣơng trình để tìm các đƣờng đi trong ma trận liên kết 3.1.1.1 Các yêu cầu đối với chƣơng trình và xây dựng chƣơng trình 3.1.1.1 Các yêu cầu đối với chƣơng trình và xây dựng chƣơng trình
Chƣơng trình đƣợc thiết kế với mục đích là tìm tất cả các đƣờng đi giữa hai nút trong ma trận liên kết, mà ma trận liên kết này đƣợc xây dựng từ đồ thị liên kết.
Tham số đầu vào của chƣơng trình là ma trận liên kết đƣợc xây dựng từ đồ thị liên kết mà các phần tử chỉ nhận giá trị 0 hoặc 1. Chƣơng trình phải hoạt động sao cho tìm đƣợc các đƣờng đi của ma trận liên kết. Tham số đầu ra của chƣơng trình là tất cả các đƣờng đi đƣợc viết dƣới dạng các phép hội sơ cấp.
Để có thể chạy đƣợc ứng dụng này thì máy tính của bạn phải có bộ nhớ tối thiểu là 32MB. Để cải tiến chƣơng trình ta phải tìm cách phát triển chức năng tìm đƣờng đi thành công của ma trận liên kết. Các tham số của chức năng này đƣợc thể hiện ở hình 3.1:
Hình 3.1: Sơ đồ mô phỏng chương trình tìm tất cả các đường đi
3.1.1.2 Lựa chọn thuật toán để viết chƣơng trình tìm tất cả các đƣờng đi giữa hai nút trong ma trận liên kết
Trong chƣơng 2 chúng ta có nói đến thuật toán tìm tất cả các đƣờng đi giữa hai nút. Thuật toán ở phần 2.1.4 nói về việc tìm tất cả đƣờng đi giữa hai nút trong ma trận liên kết, còn thuật toán ở phần 2.1.5 nói về việc tìm tất cả các đƣờng đi giữa hai nút của ma trận liên kết trong lý thuyết đồ thị. Hai thuật toán đó đều có những ƣu và nhƣợc điểm riêng.
Hàm Kích cỡ ma trận liên kết Ma trận liên kết Đỉnh đầu - nguồn Đỉnh cuối - đích Tất cả các đƣờng đi
Thuật toán ở phần 2.1.4 chỉ thích hợp với những đồ thị có kích thƣớc tƣơng đối nhỏ, trong thuật toán yêu cầu ta phải tính toán đƣợc các thành phần Bk và B*k thì mới tiến hành các bƣớc tiếp theo của thuật toán đƣợc, đồ thị có kích thƣớc lớn thì việc tính toán các thành phần này là tƣơng đối phức tạp, dài và dễ nhầm lẫn vì các phần tử của ma trận lúc này là các chuỗi dài.
Thuật toán ở phần 2.1.5 là sự phát triển hơn của thuật toán ở phần 2.1.4. Ta có thể dựa vào việc tìm đƣờng đi ngắn nhất giữa hai nút trong lý thuyết đồ thị đã đƣợc học để phát triển thành thuật toán tìm tất cả các đƣờng đi. Ý tƣởng của thuật toán này là dữ liệu đƣợc lƣu dƣới dạng ma trận liên kết. Tại giao điểm giữa cột i và hàng j của ma trận A sẽ đƣợc viết là 1 nếu cặp đỉnh xi và xj có cạnh nối với nhau, sẽ đƣợc viết là 0 nếu cặp đỉnh xi và xj không có cạnh nối với nhau. Ta có thể thấy rõ sự hoạt động của chƣơng trình này thông qua sơ đồ khối đƣợc nói đến ở phần 2.1.5.
Vậy ta sẽ sử dụng thuật toán 2.1.5 để xây dựng chƣơng trình tìm tất cả các đƣờng đi giữa hai nút trong ma trận kết nối.
3.1.1.3 Phát triển hàm tìm kiếm tất cả các đƣờng đi giữa hai nút trong ma trận liên kết
Vì các đƣờng đi mà chúng ta tìm kiếm phải là khác nhau và không lặp, nhƣ thế có nghĩa là chúng có thể khác nhau về độ dài, số đỉnh của mỗi đƣờng đi mà cũng có thể không nhƣng thứ tự trong các đƣờng đi phải khác nhau hoàn toàn. Rõ ràng nếu ta ký hiệu mỗi đỉnh là một số, thì ta có thể lƣu mỗi đƣờng đi từ đỉnh đầu (nguồn) đến đỉnh cuối (đích) nhƣ một mảng (hoặc một chuỗi) mà có chiều dài không lớn hơn kích thƣớc của ma trận liên kết và tất cả các đƣờng tìm đƣợc ta có thể lƣu vào một tập các mảng (tập các hàng - mỗi hàng là 1 mảng) do vậy số hàng chính bằng số các đƣờng đi tìm đƣợc. Để thực hiện đƣợc điều này ta phải xác định loại của tất cả các đƣờng đi nhƣ:
unsigned int K [maxN [maxK] unsigned int i_line,
unsigned int Leng [maxN]
Tất cả các đƣờng đi đƣợc lƣu trong ma trận hai chiều K, với i_line dòng, chiều dài mỗi đƣờng đi đƣợc lƣu trong ma trận Leng.
Các biến maxN (số lƣợng tối đa các đƣờng đi), maxK (kích cỡ tối đa của ma trận) phải đƣợc khai báo hạn chế để tiết kiệm tài nguyên bộ nhớ khi chạy chƣơng trình.
Tuy nhiên để viết đƣợc chƣơng trình này ta cần có thêm các tham số sau: - Số lƣợng các đỉnh trong đƣờng đi đang tìm kiếm;
- Các đƣờng đi hiện tại là một mảng số thứ tự tất cả các đỉnh của đồ thị thông qua các đƣờng dẫn đã tìm đƣợc
Các tham số của chức năng này đƣợc thể hiện ở hình 3.2:
Hình 3.2: Mô hình hàm tìm kiếm tất cả các đường đi trong ma trận liên kết.
Hàm tìm kiếm tất cả các đƣờng đi giữa hai nút trong ma trận liên kết đƣợc viết bởi ngôn ngữ C++, dƣới đây là một đoạn code khai báo cho hàm này.
/* function Find: Tim kiem vet can theo nguyen tac de quy tat ca cac duong di tu dinh Dau (I_ISTOK) den dinh cuoi I_STOK)
*/
void Find(
unsigned int A[maxK][maxK], // Ma tran lien ket
unsigned int P[maxK], // Ma tran chua cac duong di tim duoc unsigned int L, // Chieu dai cua duong di dang tim kiem unsigned int N, // Kich co cua ma tran lien ket
unsigned int i_istok, // Index ISTOK unsigned int i_stok, // Index STOK
unsigned int i_end, //Gia tri dinh cuoi trong duong di dang tim unsigned int K[maxN][maxK], //Ma tran chua cac duong di tu ISTOK unsigned int Leng[maxN], //toi STOK voi i_line dong, ma chieu unsigned int &i_line //dai duong di luu trong ma tran Leng );
3.1.2 Xây dựng chƣơng trình trực giao hoá hàm đại số logic 3.1.2.1 Các yêu cầu đối với chƣơng trình và xác định các vấn đề 3.1.2.1 Các yêu cầu đối với chƣơng trình và xác định các vấn đề
Chƣơng trình đƣợc thiết kế để thực hiện các chức năng của nó đối với trạng thái hoạt động tốt, đƣợc biểu diễn dƣới dạng hàm logic đã đƣợc trực giao hoặc trực giao không lặp. Vấn đề ở đây là tìm kiếm độ tin cậy cấu trúc của hệ thống phức tạp. Hàm Kích cỡ ma trận liên kết Ma trận liên kết Đỉnh đầu - nguồn Đỉnh cuối - đích Số lƣợng đỉnh hiện tại Chiều dài của đƣờng đi hiện tại
Đƣờng đi hiện tại trong mảng
Tham số đầu vào của chƣơng trình là hàm đại số logic đƣợc thiết lập từ tập các biến mà mô tả đặc điểm chức năng của một trạng thái hoạt động tốt trong một hệ thống phức tạp. Chƣơng trình là một quá trình thực hiện hiệu quả việc chuyển đổi một hàm đại số logic sang một hình thức trực giao hoặc trực giao không lặp.
Tham số đầu ra của chƣơng trình không phải là thực hiện chức năng của một hệ thống phức tạp mà là hàm đại số logic đã đƣợc giảm thiểu, viết dƣới dạng trực giao hoặc trực giao không lặp.
Để có thể chạy đƣợc ứng dụng này thì máy tính của bạn phải có bộ nhớ tối thiểu là 32MB.
Chƣơng trình đƣợc viết bằng ngôn ngữ lập trình C++.
Các tham số hàm trực giao đƣợc mô tả nhƣ hình 3.3 dƣới đây:
Hàm đại số logic Hàm đại số logic viết dƣới hình thức trực giao
Hình 3.3: Mô hình chức năng trực giao hoá hàm logic đại số
3.1.2.2 Phân tích và lựa chọn thuật toán trực giao hoá
Nhiệm vụ của chƣơng trình là tìm tất cả các đƣờng đi giữa 2 nút trong ma trận liên kết, giả sử chúng ta có n con đƣờng, những con đƣờng này có thể đƣợc mô tả dƣới dạng K1, K2, ... Kn phân biệt. Rõ ràng nếu hàm đại số logic đƣợc viết dƣới dạng : K1˅ K2˅ ... ˅ Kn thì đó chính là dạng chuẩn tắc tuyển của nó.
f(x) = K1˅ K2˅ ... ˅Ki˅... ˅ Kn trong đó Ki = x1 x2 ...xm với i = {1..n}.
Trong các thuật toán trực giao đã đƣợc trình bày trong phần 2.3.1 thì ta thấy thuật toán trực giao hoá theo công thức Poresky là phù hợp để viết chƣơng trình hơn cả. Công thức Poresky đƣợc sử dụng trong thuật toán là:
K1 ˅ K2 ˅ …˅ Kj ˅ ….˅ Kn = 𝐾1˄𝐾 𝐾1 2˄ 𝐾 𝐾1 𝐾2 3˄…˄ 𝐾 … 𝐾1 𝐾𝑛−1 𝑛 Công thức có thể viết dƣới dạng khác nhƣ sau:
K1 ˅ K2 ˅ …˅ Kj ˅ ….˅ Kn = 𝐾1˄ 𝐾 𝐾1 2˄ 𝐾 𝐾1 𝐾2 3˄ …˄ 𝐾 … 𝐾1 𝐾𝑛−1 𝑛 = 𝐾1˄ (𝐾 1˄𝐾2(𝐾 2˄𝐾3( 𝐾 … 𝐾3 𝑛−1˄𝐾𝑛 … ) Hàm trực giao
Ki có thể là một biến nhƣng cũng có thể là một tập các biến: Ki = x1 x2 ...xm
khi đó 𝐾𝑖 sẽ đƣợc tính nhƣ sau:
𝐾𝑖 = 𝑥 v x1 1 𝑥 v x2 1 x2 𝑥 v . . . v x3 1 x2 x3 . . . 𝑥 . 𝑚
3.1.2.3 Thiết kế các hàm chức năng cho thuật toán trực giao hoá
Chƣơng trình giải quyết một số vấn đề liên quan đến dữ liệu: Phƣơng pháp lƣu trữ dữ liệu và các kết quả, ...
Nhƣ phần trƣớc ta đã nói sau khi thực hiện hàm Find sẽ cho ta tất cả các đƣờng đi giữa đỉnh đầu và đỉnh cuối. Tất cả các đƣờng đi đƣợc lƣu trong ma trận hai chiều K, với i_line dòng, chiều dài mỗi đƣờng đi đƣợc lƣu trong ma trận Leng.
Trong khi thực hiện thuật toán trực giao hoá ta đã sử dụng các thuật toán cắt giảm, vì kết quả vẫn phải là các đƣờng đi đã đƣợc trực giao hoặc trực giao không lặp nên ta vẫn lƣu mỗi đƣờng đi vào một mảng, tập tất cả các đƣờng đi đƣợc lƣu vào một ma trận. Vì vậy tham số đầu vào và đầu ra của hàm thực hiện thuật toán trực giao hoá cũng tƣơng tự hàm Find:
unsigned int K[maxN][maxK], unsigned int i_line,
unsigned int LengК[maxN]
Ta sử dụng ngôn ngữ lập trình C++ để phát triển hàm trực giao hoá. Dƣới đây sẽ là một phần của hàm:
/* Function Ortogonal: Truc giao hoa tat ca cac thanh phan cua K1, ket qua luu trong ma tran AB, ma van giu duoc dang chuan tac tuyen truc
giao.*/
void ortogonal(
unsigned int K1[maxN][maxK], //input
unsigned int i_line,
unsigned int LengK1[maxN],
unsigned int AB[maxN][maxK], //output
unsigned int &i_line_AB, unsigned int Leng_AB[maxN] );