1. Trang chủ
  2. » Khoa Học Tự Nhiên

THUẬT TOÁN LOANG

34 384 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 34
Dung lượng 362,5 KB

Nội dung

Bây giờ ta đưa ra thứ tự duyệt các đỉnh của đồ thị đã cho theo thuật toán tìm kiếm theo chiều rộng; thứ tự duyệt có thể bắt đầu từ một đỉnh v nào đó.. + Đối với dữ liệu vào mà quan hệ gi

Trang 1

THUẬT TOÁN LOANG

-I) ĐẶT VẤN ĐỀ:

Thuật toán Loang thực chất là thuật toán tìm kiếm theo chiều rộng trên đồ thị (Breadth First

Search) Để hiểu rõ bản chất của thuật toán này, ta xét bài toán ‘Thăm các đỉnh của một đồ thị’ như sau: Cho một đồ thị vô hướng G = (V,E), N đỉnh và M cạnh (số hiệu của các đỉnh là 1,2,

…,N) Bây giờ ta đưa ra thứ tự duyệt các đỉnh của đồ thị đã cho theo thuật toán tìm kiếm theo chiều rộng; thứ tự duyệt có thể bắt đầu từ một đỉnh v nào đó Tư tưởng của thuật toán là sử dụng cấu trúc dữ liệu kiểu hàng đợi (QUEUE - vào trước ra trước) Phần tử được nạp vào đầu tiên của QUEUE là đỉnh v Sau đó cứ mỗi đỉnh p lấy ra khỏi QUEUE là ta thăm đỉnh đó đồng thời nạp vào QUEUE những đỉnh chung cạnh với p (chỉ nạp vào những đỉnh chưa xét đến) Quá trình trên được lặp đi lặp lại cho đến khi nào QUEUE rỗng thì dừng

QUEUE = ; {Khởi tạo QUEUE ban đầu là rỗng}

QUEUE <= v; {Nạp đỉnh v vào QUEUE}

Chuaxet[v]:=False;{Đỉnh v nạp vào QUEUE là đã xét rồi => cờ của v là False}

While QUEUE ≠ do

Begin

P <= QUEUE; {Lấy p từ QUEUE}

Thăm đỉnh p;

For u € Ke(p) do {Những đỉnh u chung cạnh với đỉnh p}

If Chuaxet(u) then {Nếu đỉnh u chưa xét đến}

Begin

QUEUE <= u; {Nạp u vào QUEUE}

Chuaxet[u]:=False; {Đỉnh u đã xét rồi =>cờ của u là False }

Người ta thường dùng dữ liệu kiểu mảng để biểu diễn cấu trúc dữ liệu kiểu hàng đợi QUEUE

và sử dụng 2 biến Dau và Cuoi để điều khiển việc nạp vào và lấy phần tử ra (biến Dau điều khiển thao tác lấy ra, biến Cuoi điều khiển thao tác nạp vào)

Với bài toán trên ta sử dụng mảng 1 chiều Q: Array[1 N] of Byte để biểu diễn QUEUE Khi

đó thao tác nạp vào và lấy ra được thực hiện như sau:

FillChar(Q,SizeOf(Q),0); {Khởi tạo tất cả các phần tử của Q có giá trị 0}

Dau:=1;

Cuoi:=1;

Q[cuoi]:=v; {Ban đầu nạp đỉnh v vào Q}

Để nạp thêm đỉnh u nào đó vào Q ta thực hiện:

Cuoi:=Cuoi+1; {Hoặc dùng lệnh Inc(Cuoi)}

Trang 2

Để lấy một đỉnh p nào đó ra khỏi Q ta thực hiện:

P:=Q[Dau];

Inc(Dau);

Lưu ý: Ta nói lấy đỉnh p ra khỏi hàng đợi Q là lấy ra theo cơ chế điều khiển ( vì biến Dau đã

tăng lên một đơn vị qua lệnh Inc(Dau)); về mặt vật lý thì p vẫn đang nằm trong mảng Q Như vậy ta phải hiểu rằng các phần tử trong cấu trúc hàng đợi Q là các phần tử Q[Dau], ,Q[Cuoi]

A:Array[1 Nmax,1 Nmax] of 0 1;{Nếu có cạnh giữa đỉnh i và đỉnh j thì A[i,j]=1, ngược lại A[i,j]=0 }

Chuaxet:Array[1 Nmax] of Boolean;{Cờ của các đỉnh, có trạng thái True nếu chưa xét, ngược lại False} Q:Array[1 Nmax] of Byte; {Biểu diễn hàng đợi QUEUE}

Trang 3

dau:=dau+1; {Lấy đỉnh p ra khỏi Q }

If (dau-1) mod 14 = 0 then Writeln(p:4) {In ra số hiệu đỉnh p - thao tác thăm đỉnh p}

Else Write(p:4); {trên màn hình xuất hiện mỗi dòng không quá 14 số}

Chương trình trên thực hiện với dữ liệu vào là tệp TKR_DT.INP có cấu trúc:

- Dòng đầu tiên, được gọi là dòng 0: ghi các số nguyên dương N, x cách nhau ít nhất là một ký tự trống (N: Số đỉnh của đồ thị; x: Đỉnh xuất phát);

- Trong các dòng tiếp theo: Dòng thứ i (i = 1 N-1) ghi N-i số 0 và 1 liên tiếp nhau cho biết giữa đỉnh i và đỉnh j có cạnh nối với nhau hay không (j = i + 1 N) Nếu số ghi ở vị trí j-i tính từ trái sang phải trên dòng thứ i có giá trị 1 thì có cạnh nối giữa đỉnh i và đỉnh j, nếu là giá trị 0 thì không có cạnh nối

Ví dụ với tệp TKR_DT.INP sau đây:

13 1101000000010010000000000001000000011000000101100001000001000000

Trang 4

10000 0000 110 10 0 Với tệp dữ liệu vào như trên ta phải hiểu như sau:

+ Ở dòng 0: N=13, x=1;

+ Ở dòng 1: 101000000010

- giữa đỉnh 1 với đỉnh 2 có cạnh nối với nhau

- giữa đỉnh 1 với đỉnh 3 không có cạnh nối với nhau

- giữa đỉnh 1 với đỉnh 4 có cạnh nối với nhau

- giữa đỉnh 1 với đỉnh 5 không có cạnh nối với nhau

- giữa đỉnh 1 với đỉnh 11 không có cạnh nối với nhau - giữa đỉnh 1 với đỉnh 12 có cạnh nối với nhau - giữa đỉnh 1 với đỉnh 13 không có cạnh nối với nhau + Ở dòng 2: 01000000000 - giữa đỉnh 2 với đỉnh 3 không có cạnh nối với nhau - giữa đỉnh 2 với đỉnh 4 có cạnh nối với nhau

+ Ở dòng 11: 10 - giữa đỉnh 11 với đỉnh 12 có cạnh nối với nhau - giữa đỉnh 11 với đỉnh 13 không có cạnh nối với nhau + Ở dòng 12: 0 - giữa đỉnh 12 với đỉnh 13 không có cạnh nối với nhau Quan hệ giữa các đỉnh được mô tả qua đồ thị sau:

2 3 5

7 8

4

1 6 9

12 13

10 11

Thứ tự các đỉnh được nạp vào hàng đợi Q và lấy ra tuần tự như sau:

Các phần tử

nạp vào Q

Các phần tử

có trạng thái

cờ là False

Các phần tử trong Q

Phần tử lấy

ra khỏi Q

Không nạp phần tử nào

khi lấy 2 ra khỏi Q

Trang 5

khi lấy 10 ra khỏi Q

+ Với những bộ test dữ liệu bé thì ta có thể tạo một cách thủ công Nhưng với những bộ test

dữ liệu lớn thì ta phải tạo bằng chương trình Sau đây xin giới thiệu chương trình tạo bộ test với số lượng các đỉnh của đồ thị là 253:

Trang 6

+ Đối với dữ liệu vào mà quan hệ giữa các đỉnh có dạng là một ma trận đầy đủ (ma trận đối xứng) và các số ghi trên mỗi dòng cách nhau ít nhất là một ký tự trống thì ta thay thủ tục đọc tệp bởi thủ tục sau đây:

Bạn đọc tự viết thủ tục đọc tệp trong trường hợp dữ liệu vào mà quan hệ giữa các đỉnh có dạng

là nữa trên hoặc nữa dưới của một ma trận đầy đủ và các số ghi trên mỗi dòng cách nhau ít nhất là một ký tự trống hoặc liền nhau

II) CÁC BÀI TOÁN ÁP DỤNG:

Bài 1: Tìm đường đi qua ít đỉnh nhất

Cho đồ thị vô hướng G = (V,E) có N đỉnh và M cạnh (các đỉnh có số hiệu là 1,2, ,N) Mối quan hệ giữa các đỉnh được cho bởi ma trận kề A[i,j]: nếu đỉnh i và đỉnh j có chung cạnh thì A[i,j] = 1, ngược lại A[i,j] = 0

Yêu cầu:

1) Tìm đường đi qua ít đỉnh nhất giữa 2 đỉnh bất kỳ nào đó của đồ thị

2) Tìm số lượng các thành phần liên thông của đồ thị (các đỉnh thuộc một vùng liên thông nếu luôn tồn tại đường đi giữa 2 đỉnh bất kỳ trong các đỉnh đó)

Trang 7

Bàn về dung lượng bộ nhớ: Chương trình trên thực hiện với giá trị tối đa là 253 đỉnh của đồ

thị Vậy với đồ thị có số đỉnh lớn hơn 253 thì ta giải quyết thế nào?

Bài toán sau đây đưa ra một giải pháp để xử lý:

Bài 2: Đường đi trong đồ thị có nhiều đỉnh

Cho một đồ thị vô hướng có N đỉnh (N<=500000), các đỉnh có số hiệu là 1 N Hãy tìm đường

đi qua ít đỉnh nhất giữa 2 đỉnh x và y nào đó cho trước của đồ thị

Dữ liệu vào là tệp văn bản dothi.inp có cấu trúc:

- Dòng đầu tiên ghi các số N, x, y;

- Các dòng tiếp theo, mỗi dòng ghi 2 số là số hiệu của 2 đỉnh có chung cạnh;

- Các số ghi trên mỗi dòng cách nhau ít nhất là một ký tự trống

Dữ liệu ra là tệp văn bản dothi.out ghi số hiệu các đỉnh trong đường đi tìm được giữa 2 đỉnh x

và y, mỗi số ghi trên 1 dòng Nếu không tồn tại đường đi thì ghi thông báo ‘Khong ton tại duong di’

Phân tích:

Trang 8

Nhìn dạng bài toán, chúng ta nhận thấy ngay thuật toán tối ưu để xử lý là thuật toán Loang Nhưng vì số đỉnh của đồ thị nằm trong phạm vi quá lớn (N<=500000) nên ta không thể sử dụng kiểu dữ liệu mảng để lưu trữ thông tin về các đỉnh và biểu diễn cấu trúc hàng đợi Vậy làm thế nào?

Tôi xin đưa ra một giải pháp: Lưu trữ các thông tin trong quá trình xử lý cũng như biểu diễn

cấu trúc hàng đợi để ‘Loang’ là bởi các tệp văn bản (vì chúng ta đã biết tệp là kho chứa dữ

liệu dường như vô tận).

Cụ thể như sau:

- Sử dụng hệ thống tệp văn bản *.ke để lưu các đỉnh chung cạnh với đỉnh có số hiệu

là giá trị số của phần đầu tên tệp: Ví dụ tệp 2.ke sẽ lưu trữ số 1 và số 4, mỗi số ghi trên một dòng

- Sử dụng hệ thống các tệp văn bản *.dd chứa số 1 hoặc 0 cho biết đỉnh có số hiệu là giá trị số của phần đầu tên tệp đã bị đánh dấu hay chưa; giá trị 1: đỉnh đó đã xét rồi, ngược lại là chưa xét Ví dụ tệp 5.dd chứa số 1 có nghĩa là đỉnh 5 đã được xét rồi trong quá trình ‘Loang’ (đã được nạp vào hàng đợi).Hệ thống tệp này khởi tạo ban đầu là chứa số 0

- Sử dụng hệ thống tệp văn bản *.tr chứa một số nguyên là số hiệu của đỉnh trước đỉnh có số hiệu là giá trị số của phần đầu tên tệp khi nạp vào hàng đợi Ví dụ tệp 6.tr chứa số 4 có nghĩa là đỉnh 6 được nạp vào hàng đợi nhờ đỉnh 4

- Sử dụng hệ thống các tệp *.que để biểu diễn cấu trúc hàng đợi Ví dụ dau = 1 và cuoi = 4 thì đỉnh đầu tiên của hàng đợi là đỉnh có số hiệu là số được chứa trong tệp 1.que Tương tự, với đỉnh thứ 2, thứ 3, thứ 4, của hàng đợi

- Sử dụng hệ thống các tệp văn bản *.kq để lưu các đỉnh trong quá trình lấy kết quả

Hệ thống các tệp văn bản trên được đưa ra ở phần khai báo hằng:

Trang 9

Để nạp đỉnh v vào hàng đợi ta thực hiện:

Trang 11

Readln(f1,ok); {Kiểm tra xem v đã bị đánh dấu hay chưa}

Close(f1);

If ok=0 then Begin Assign(f1,s2+dd);

Str(dem,s1);

Assign(f1,s1+kq);

Rewrite(f1);

Writeln(f1,i);

Trang 12

+ Ta có thể tham khảo chương trình sau đây để tạo các bộ test dữ liệu lớn:

Trang 13

If (yd=0) or (yd=xn) then

While (yd=0) or (yd=xn) do yd:=Random(MN+1);

Writeln(‘Hai đinh can tim duong di la:’,xn,’ ‘,yd);

Until Readkey = #27; {Khi nào thấy đạt yêu cầu rồi thì ấn phím ESC để dừng}

Trạng thái 1 Trạng thái 0

Hình 1

Trang 14

tự trong xâu S thể hiện việc quả cầu vào lối vào với tên ký tự đó

Ví dụ: S=AABC có nghĩa là ta lần lượt thả quả cầu vào các lối A, A, B, C

Bài toán đặt ra như sau: Cho hai trạng thái bất kỳ T1, T2 của Otomat Hãy tìm một ký tự S ngắn nhất có thể được thể hiện hoạt động của Otomat chuyển từ trạng thái T1 đến trạng thái T2

Dữ liệu vào là tệp otomat.inp cócấu trúc:

- Dòng thứ nhất ghi 8 số 0 và 1 biểu diễn trạng thái T1;

- Dòng thứ hai ghi 8 số 0 và 1 biểu diễn trạng thái T2;

Các số trên mỗi dòng được ghi liên tiếp nhau

Dữ liệu ra là tệp otomat.out ghi xâu ký tự S tìm được Nếu không tìm được xâu S thì ghi ký tự

Trang 15

If T[4]='0' then Begin T[4]:='1';

If T[6]='0' then T[6]:='1' else T[6]:='0';

End else {T[4]='1'}

Begin T[4]:='0';

If T[7]='0' then T[7]:='1' else T[7]:='0';

End;

Trang 16

If T[6]='0' then T[6]:='1' Else T[6]:='0';

End Else {T[4]='1'}

If T[5]='0' then Begin T[5]:='1';

If T[7]='0' then T[7]:='1' else T[7]:='0';

End Else {T[5]='1'}

Begin T[5]:='0';

If T[8]='0' then T[8]:='1' else T[8]:='0';

If T[7]='0' then T[7]:='1' else T[7]:='0'

End Else {T[5]='1'}

Trang 17

Begin T[5]:='0';

If T[8]='0' then T[8]:='1' else T[8]:='0';

End;

End Else {T[3]='1'}

Begin T[3]:='0';

If T[8]='0' then T[8]:='1' else T[8]:='0';

If i=1 then O:=Tha_A(P);

If i=2 then O:=Tha_B(P);

If i=3 then O:=Tha_C(P);

If i=1 then S[cuoi]:='A';

If i=2 then S[cuoi]:='B';

If i=3 then S[cuoi]:='C';

Trang 18

Bài 5: Máy đổi thẻ tự động

Có một máy giải trí tự động có M cửa dùng để đổi thẻ Có các thẻ mã số từ 1, ,N Nếu ta bỏ thẻ có mã số i vào một cửa nào đó thì máy sẽ thu thẻ đó và cho ra một thẻ có mã số nào đó trong khoảng 1 N Máy đổi thẻ hoạt động theo thông tin ghi trong tệp văn bản the.inp :

- Dòng đầu tiên ghi các số N, M;

- N dòng tiếp theo, mỗi dòng chứa M số tạo thành một bảng có kích thước N x M Phần tử nằm trên dòng i, cột j của bảng này cho biết nếu ta bỏ thẻ có số hiệu i vào cửa j thì sẽ thu được thẻ có số hiệu chính là giá trị của phần tử đó

Các số trên mỗi dòng của tệp ghi cách nhau ít nhất là một ký tự trống

Yêu cầu:

Với mỗi cặp thẻ có số hiệu x và y cho trước (x<>y), hãy cho biết có cách nào nhanh nhất

để dùng thẻ có số hiệu x thu được thẻ có số hiệu y hay không?

Dữ liệu ra là tệp văn bản the.out trình bày theo dạng:

Bỏ thẻ x vào cửa thu được thẻ

Bỏ thẻ vào cửa thu được thẻ y

Nếu không tìm được cách để từ thẻ có số hiệu x thu được thẻ có số hiệu y thì ghi vào tệp thông báo ‘Tu the x khong thu duoc the y’

Ví dụ:

Tệp

Doithe.inp

Tệp Doithe.out

Tệp Doithe.inp

Tệp Doithe.out

Bo the 2 vao cua 1 thu duoc the 3

Bo the 3 vao cua 1 thu duoc the 1 5 4 4 5

Tu the 4 khong thu duoc the 5

Phân tích: Bài toán trên thuộc lớp các bài toán biến đổi trạng thái Hơn nữa yêu cầu tìm kết

quả qua ít bước thao tác nhất nên ta sử dụng thuật toán Loang là thích hợp nhất

Cụ thể như sau:

Ta sử dụng ma trận A[i,j] (i = 1 N, j = 1 M) để lưu giữ thông tin quan hệ giữa thẻ - cửa đã cho trong tệp dữ liệu vào Ta phải hiểu: Bỏ thẻ i vào cửa j thu được thẻ A[i,j]

Cấu trúc dữ liệu hàng đợi được biểu diễn bởi mảng một chiều Q

Ta phải tìm các thao tác sao cho từ thẻ x thu được thẻ y một cách nhanh nhất

Đầu tiên ta cho thẻ x vào Q

Trang 19

Cứ mỗi lần lấy một thẻ p ra từ Q ta lại nạp vào Q những thẻ có thể thu được từ thẻ p (chỉ nạp những thẻ chưa có trong Q, hàm vitri(v) cho biết thẻ v có ở trong Q hay không: Giá trị của hàm bằng 0 thì thẻ v chưa có trong Q, ngược lại thì đã có).

Khi nạp một thẻ vào Q ta phải lưu giữ thông tin thẻ đó có được từ thẻ nào và bỏ vào cửa nào

để sau này truy xuất kết quả (mảng một chiều TRUOC có nhiệm vụ đó)

Quá trình trên lặp đi lặp lại cho đến khi hàng đợi Q rỗng (dau > cuoi)

Kết thúc quá trình ‘Loang’, dựa vào mảng TRUOC ta truy xuất kết quả bằng thủ tục đệ quy Ketqua(y)

Khi truy xuất kết quả ta phải hiểu rằng nếy TRUOC[y].the = 0 thì có nghiã là thẻ y không thu được từ một thẻ nào cả

Lưu ý: một thẻ i bỏ vào một của j nào đó thì vẫn có thể thu được thẻ i.

Sau đây là toàn văn chương trình:

A:Array[1 Nmax,1 Mmax] of Byte; {Quan hệ Thẻ - Cửa}

Q:Array[1 Nmax] of Byte; {Hàng đợi - chứa các thẻ thu được từ thẻ x}

Trang 21

Bài tập: Cũng bài toán trên nhưng yêu cầu từ thẻ x thu được thẻ có số hiệu lớn nhất một cách

nhanh nhất (thẻ có số hiệu lớn nhất trong các thẻ thu được từ thẻ x)

Bài 5: Đường đi của Robot (Đề thi HSG lớp 12 năm học 2009 - 2010, Tỉnh Hà Tĩnh)

Một bảng hình chữ nhật có kích thước MxN (M,N nguyên dương và không lớn hơn 100) được chia thành các ô vuông đơn vị bằng các đường thẳng song song với các cạnh Một số ô vuông nào đó có thể đặt các vật cản Từ một ô vuông, Robot có thể đi đến một ô vuông kề cạnh với nó nếu ô vuông đó không có vật cản Hỏi rằng nếu Robot bắt đầu xuất phát từ một ô vuông không có vật cản thuộc dòng K, cột L thì có thể đi đến được ô vuông không có vật cản thuộc dòng H, cột O hay không? Nếu có thì hãy chỉ ra đường đi qua ít ô vuông nhất

Dữ liệu vào là tệp văn bản BAI3.INP có cấu trúc:

- Dòng đầu tiên ghi các chữ số M, N, K, L, H, O Các số ghi cách nhau ít nhất một ký tự trống;

- M dòng tiếp theo, mỗi dòng ghi N số 1 hoặc 0 tuỳ thuộc vào ô vuông tương ứng trong bảng hình chữ nhật nêu trên có vật cản hay không (ghi số 1 nếu có vật cản); các số trên mỗi dòng ghi liên tiếp nhau

Dữ liệu ra là tệp văn bản BAI3.OUT có cấu trúc:

Nếu Robot có thể đi được từ ô vuông thuộc dòng K, cột L đến ô vuông thuộc dòng H, cột

O thì:

- Dòng đầu tiên ghi ‘Co duong di ‘;

- Các dòng tiếp theo, mỗi dòng ghi 2 số là chỉ số dòng và chỉ số cột của các ô vuông trong đường đi tìm được từ ô vuông thuộc dòng K, cột L đến ô vuông thuộc dòng H, cột O mà qua ít

ô vuông nhất Hai số trên mỗi dòng ghi cách nhau ít nhất một ký tự trống;

- Ngược lại, nếu Robot không thể đi được từ ô vuông thuộc dòng K, cột L đến ô vuông thuộc dòng H, cột O thì ghi ‘Khong co duong di’

Ví dụ 1:

Tệp robot.inp:

4 7 3 4 2 61000000001010000000001101000

Tệp robot.out:

Khong co duong di

Phân tích:

Ngày đăng: 07/12/2015, 13:24

TỪ KHÓA LIÊN QUAN

w