Tải bản đầy đủ (.docx) (3 trang)

bµi to¸n lan ch­¬ng ii bµi to¸n lan bµi to¸n lan lµ mét bµi to¸n c¬ b¶n cã nhiòu øng dông trong viöc gi¶i mét sè ®ò thi häc sinh giái tin häc nã th­êng ®­îc m« t¶ d­íi m« h×nh cña lý thuyõt ®å thþ víi

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 (58.6 KB, 3 trang )

<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1>

<b>chơng ii</b>
<b>bài toán lan</b>


<i>Bi toỏn lan</i> l một bài tốn cơ bản có nhiều ứng dụng trong việc giải một số đề
thi học sinh giỏi Tin học. Nó thờng đợc mơ tả dới mơ hình của lý thuyết đồ thị với nhiều
tên gọi khác nhau: <i>bài toán tìm kiếm, bài tốn duyệt, bài tốn đi thăm, ...</i> Ta có thể mơ
phỏng bài tốn này nh sau:


Xét một tập hợp các phần tử nào đấy, trên đó đã định nghĩa một quan hệ 2-ngôi
giữa các phần tử gọi là quan hệ <i>kề</i>: thế nào là phần tử B kề với phần tử A. Dới mơ hình đồ
thị, các phần tử đợc gọi là các <i>nút</i> hay các <i>đỉnh</i>, và nếu đỉnh B kề với đỉnh A thì ta nói có
một <i>cạnh</i> đi từ A đến B. Quan hệ kề có thể là đối xứng hay khơng đối xứng. Nếu quan hệ
này là đối xứng thì cạnh xác định tơng ứng là <i>vô hớng</i> (nghĩa là cạnh đi từ A đến B cũng
chính là cạnh đi từ B đến A), trái lại, cạnh là <i>có hớng</i>. Quan hệ kề c m rng theo lut


<i>bắc cầu</i> thành quan hệ <i>lan</i>:


- mọi phần tử A xem nh lan đợc tới chính nó,
- nếu B kề với A thì A lan đợc tới B,


- nếu A lan đợc tới B, đồng thời B lan đợc tới C thì A lan đợc tới C.


Trong lý thuyết đồ thị, ngời ta thờng nói khi A lan đợc tới B là từ A có <i>đờng đi</i> tới
B, hay từ A có thể <i>đi thăm</i> B. Bài toán đặt ra là xác định tập hợp tất cả các phần tử có thể
lan đợc từ một phần t xut phỏt ó cho.


Có hai phơng pháp lan chủ yếu: lan theo <i>chiều rộng</i> và lan theo <i>chiều sâu</i>.
<b>1. Lan theo chiÒu réng</b>


T tởng cơ bản của phơng pháp này là từ những phần tử đã đợc lan, ta lan dần sang
các phần tử khác <i>theo từng mức kề</i> với phần tử đang xét. Có hai thao tác đợc lặp lại trong


quá trình lan: lấy một phần tử từ tập hợp các phần tử đã đợc lan làm điểm xuất phát và kết
nạp các phần tử kề với phần tử này vào tập hợp các phần tử đã đợc lan. Dĩ nhiên, để vòng
lặp kết thúc đợc, những phần tử đợc lấy ra phải loại khỏi tập hợp đang xét và những phần
tử thêm vào phải là những phần tử cha đợc kết nạp lần nào. Quá trình lan sẽ kết thúc khi
tập hợp các phần tử đã đợc lan đang xét là rỗng và khi ấy, những phần tử nào đã đợc xét
kết nạp là những phần tử đợc lan từ phần tử ban đầu.


Về mặt dữ liệu, tập hợp các phần tử đã đợc lan đợc tổ chức nh một <i>hàng đợi</i>, trong
đó có hai thao tác: lấy ra một phần tử ở đầu hàng đợi và kết nạp một phần tử vào cuối
hàng đợi. Thuật toán lan theo chiều rộng, bắt đầu từ phần tử S, có thể mơ tả bằng đoạn
ch-ơng trình PASCAL (mơ phỏng) dới đây:


Enter;
Init;


Append_To_Queue(S);


While <Hàng đợi khác rỗng> do
begin


Extract_From_Queue(X);


For <Y cha đợc kết nạp và Y kề với X> do
Append_To_Queue(Y);


end;
Result;


trong đó, thủ tục <i>Enter</i> nhập các thông tin về quan hệ kề và phần tử xuất phát, thủ tục <i>Init</i>



</div>
<span class='text_page_counter'>(2)</span><div class='page_container' data-page=2>

Có thể có nhiều cách tổ chức một hàng đợi. Đơn giản hơn cả (khi bộ nhớ cho
phép), hàng đợi đợc tổ chức nh một mảng Q[1..N] lấy giá trị trên các phần tử, trong đó N
là số phần tử đợc xét. Để quản lý hàng đợi này, ta thêm vào các biến nguyên <i>first, last</i> để
chỉ các vị trí đầu và cuối hàng đợi. Nh vậy, số phần tử hiện có của hàng đợi đợc xác định
bởi <i>last-first+1</i>. Các thao tác trên hàng đợi lúc này là:


- khởi tạo hàng đợi rỗng:


<i>first := 1; last := 0;</i>


- lấy X ra khỏi hàng đợi:


<i>X := Q[first]; first := first+1;</i>


- kết nạp X vào hàng đợi:


<i>last := last+1; Q[last] := X;</i>


<b>2. Lan theo chiỊu s©u</b>


Khác với lan theo chiều rộng là lan theo từng mức kề (vì thế các phần tử đ ợc lan
theo mọi hớng), lan theo chiều sâu là <i>lan theo một hớng đã chọn</i> cho đến khi khơng lan
thêm đợc nữa thì lùi lại lan theo hớng khác. Để quá trình lan là kết thúc, tất nhiên không
đợc lan lại những phần tử đã lan rồi. Thực chất đây là phơng pháp quay lui để duyệt mọi
hớng lan có thể có và ta có thể dùng thủ tục đệ quy <i>Depth_Expand(X)</i> dới đây để mô tả
việc lan theo chiều sâu từ X (kiểu của các phần tử đợc định nghĩa bởi tên <i>Elements</i>):
Procedure Depth_Expand(X: Elements);


Var Y: Elements;
Begin



<đánh dấu đã lan cho X>;


For <Y cha lan vµ Y kỊ víi X> do Depth_Expand(Y);
End;


Việc dùng thủ tục đệ quy sẽ tổ chức lu trữ các thơng tin của q trình lan theo cơ
cấu <i>ngăn xếp</i>. Bài toán lan bắt đầu từ S lúc này đợc giải theo mơ hình sau:


Enter;
Init;


Depth_Expand(S);
Result;


trong đó các thủ tục <i>Enter</i> và <i>Result</i> đợc thiết kế giống nh trớc, thủ tục <i>Init</i> khởi tạo giá trị
cha đợc lan cho tất c cỏc phn t.


<b>3. Miền liên thông</b>


Nu quan h k cho trên tập hợp đang xét là đối xứng (khi đó đồ thị tơng ứng gọi
là <i>vơ hớng</i> vì các cạnh của nó đều là vơ hớng) - nghĩa là A kề với B kéo theo B kề với A
(vì thế ngời ta thờng nói trong trờng hợp này là chúng <i>kề nhau</i>), thì tập hợp đang xét sẽ
đ-ợc chia thành những lớp rời nhau từng đôi và những lớp này phủ kín tập hợp đang xét, sao
cho hai phần tử của cùng một lớp là lan đợc sang nhau và hai phần tử khác lớp là không
lan đợc sang nhau. Ngời ta gọi mỗi lớp nh vậy là một <i>miền liên thông</i> hay ngắn gọn - một


<i>miền</i> - của quan hệ kề đã cho. Nh vậy mỗi miền liên thông sẽ đợc xác định duy nhất bởi
một phần tử bất kỳ thuộc nó. Mọi phần tử khác của miền sẽ đợc nhận bằng cách lan từ
phần tử này. Để duyệt các miền liên thông, cần đánh dấu những phần tử nào đã đợc lan,


và quá trình duyệt đợc tiến hành bằng cách bắt đầu từ những phần tử cha đánh dấu lan ra
những phần tử khác. Việc duyệt các miền liên thơng có thể mơ tả qua đoạn chơng trình:
Init;


</div>
<span class='text_page_counter'>(3)</span><div class='page_container' data-page=3>

if <X cha đợc lan> then Expand(X);


trong đó <i>Init</i> là thủ tục khởi tạo giá trị cha đợc lan cho mọi phần tử và <i>Expand(X)</i> là thủ
tục lan bắt đầu từ X. Thủ tục <i>Expand(X)</i> có thể đợc thiết kế lan theo chiều rộng hoặc lan
theo chiều sâu nh đã trình bày. Mỗi lần thực hiện thủ tục này là một lần một miền liên
thơng đợc xác định.


Thơng thờng, trong q trình duyệt các miền liên thông, ta muốn ghi nhận lại mỗi
phần tử là thuộc miền nào. Để làm điều này, ngời ta thờng tổ chức một mảng nguyên
L[...], với các chỉ số chạy trên các phần tử, ghi nhận số hiệu miền của phần tử tơng ứng
(các miền đợc đánh số hiệu 1, 2, ...). Mảng này cũng dùng để ghi nhận phần tử tơng ứng
đã đợc lan hay cha với quy ớc L[X] = 0 nghĩa là X cha đợc lan. Đoạn chơng trình trên đợc
sửa lại chút ít nh sau:


Init; k := 0;


For <X thuộc tập hợp các phần tö> do
if L[X] = 0 then


begin


k = k+1;
Expand(X);
end;





trong đó việc gán giá trị cha đợc lan cho mọi X trong <i>Init</i> đợc thay bởi việc gán 0 cho mọi
L[X], và thao tác đánh dấu cho các phần tử đợc lan Y trong <i>Expand(X)</i> đợc thay bởi thao
tác gán giá trị k cho L[Y]. Sau đoạn chơng trình, biến k sẽ lu trữ số miền liên thông đã
xác định.


Chú ý rằng, với quan hệ kề không đối xứng (tơng ứng với đồ thị có hớng), khơng
có khái niệm miền liên thơng nh ó trỡnh by.


<b>4. Các bài toán lan trên bảng</b>


</div>

<!--links-->

×