1. Trang chủ
  2. » Cao đẳng - Đại học

BÀI TẬP LỚN MÔN Cấu trúc dữ liệu và giải thuật ĐƯỜNG ĐI NGẮN NHẤT

11 1,3K 5

Đ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 11
Dung lượng 67 KB

Nội dung

I.BÀI TOÁN ĐƯỜNG ĐI NGẮN NHẤT. 1.Phát biểu bài toán. Trong các ứng dụng thực tế bài toán tìm đường đi ngắn nhất giữa hai đỉnh của một đồ thị có ý nghĩa to lớn. Có thể dẫn về bài toán như vậy nhiều bài toán thực tế quan trọng. Ví dụ: ỉBài toán chọn một hành trình tiết kiệm nhất (theo tiêu chuẩn khoảng cách hoặc thời gian, chi phí ...) trên một bản đồ đường giao thông. ỉBài toán chọn một phương pháp tiết kiệm nhất để đưa một hệ động lực từ trạng thái này sang trạng thái khác. ỉĐặc biệt, bài toán tìm hành trình trong nhiều công đoạn nào đó thuộc một qui trình công nghệ sản xuất tự động. Ví dụ trong công đoạn khoan mạch in, hàn chân các linh kiện điện tử trong các nhà máy sản xuất, lắp ráp mạch điện tử, hành trình làm việc của các máy khoan tự động, robot hàn thường gồm rất nhiều đỉnh: hàng nghìn, hàng chục nghìn đỉnh. Vậy nênviệc thực hiện được hành trình ngắn nhất cho các robot đem lại lợi ích to lớn: tăng năng suất, giảm chi phí... (có thể trong trường hợp này bài toán biến đổi đi một chút, ví dụ cần phải tìm hành trình ngắn nhất qua tất cả các đỉnh, mỗi đỉnh đúng một lần...) ỉVà nhiều bài toán thực tế khác ... Hiện nay có rất nhiều phương pháp để giải các bài toán như vậy. Thế nhưng thông thường các phương pháp dựa trên lý thuyết đồ thị tỏ ra là các phương pháp có hiêụ quả cao nhất. Bài toán tìm đường đi ngắn nhất dưới dạng tổng quát có thể phát biểu như sau: Cho một đồ thị G(V, E), một hàm trọng số w(e) cho các cung e của G. Bài toán đặt ra là cần tìm một đường đi ngắn nhất từ một đỉnh xuất phát sG đến đỉnh cuối dG. Các trọng số w(e) có thể là dương, âm hoặc bằng 0. Một điều duy nhất là G không chứa chu trình với tổng trọng số âm. Vì rằng nếu như G có một chu trình H như vậy thì xuất phát từ S, ta đi đến vH và sau đó đi vòng quanh chu trình H một số đủ lớn lần rồi đến d ta sẽ thu được một đường đi có trọng lượng đủ nhỏ . Vì vậy trong trường hợp này đường đi ngắn nhất là không tồn tại. Tuy nhiên, việc giải bài toán tổng quát trên là nằm ngoài khuôn khổ bài tập lớn này, vì vậy chúng ta chỉ giải bài toán đặt ra trong trường hợp các trọng số w(e) 0, G là đồ thị định hướng. Ta xét một thuật toán đơn giản, hiệu quả để giải bài toán trong trường hợp này.

Trang 1

Bài tập lớn môn

Cấu trúc dữ liệu và giải thuật

Đờng đi ngắn nhất

I Bài toán đờng đi ngắn nhất.

1 Phát biểu bài toán.

Trong các ứng dụng thực tế bài toán tìm đờng đi ngắn nhất giữa hai đỉnh của một đồ thị có ý nghĩa to lớn Có thể dẫn về bài toán nh vậy nhiều bài toán thực tế quan trọng

Ví dụ:

 Bài toán chọn một hành trình tiết kiệm nhất (theo tiêu chuẩn khoảng cách hoặc thời gian, chi phí ) trên một bản đồ đờng giao thông

 Bài toán chọn một phơng pháp tiết kiệm nhất để đa một hệ động lực từ trạng thái này sang trạng thái khác

 Đặc biệt, bài toán tìm hành trình trong nhiều công đoạn nào đó thuộc một qui trình công nghệ sản xuất tự động Ví dụ trong công đoạn khoan mạch in, hàn chân các linh kiện điện tử trong các nhà máy sản xuất, lắp ráp mạch điện tử, hành trình làm việc của các máy khoan tự động, robot hàn thờng gồm rất nhiều đỉnh: hàng nghìn, hàng chục nghìn đỉnh Vậy nênviệc thực hiện đợc hành trình ngắn nhất cho các robot đem lại lợi ích to lớn: tăng năng suất, giảm chi phí (có thể trong trờng hợp này bài toán biến đổi đi một chút, ví dụ cần phải tìm hành trình ngắn nhất qua tất cả các đỉnh, mỗi

đỉnh đúng một lần )

 Và nhiều bài toán thực tế khác

Hiện nay có rất nhiều phơng pháp để giải các bài toán nh vậy Thế nhng thông th-ờng các phơng pháp dựa trên lý thuyết đồ thị tỏ ra là các phơng pháp có hiêụ quả cao nhất

Bài toán tìm đờng đi ngắn nhất dới dạng tổng quát có thể phát biểu nh sau:

Cho một đồ thị G(V, E), một hàm trọng số w(e) cho các cung e của G Bài toán đặt

ra là cần tìm một đờng đi ngắn nhất từ một đỉnh xuất phát sG đến đỉnh cuối dG Các trọng số w(e) có thể là dơng, âm hoặc bằng 0 Một điều duy nhất là G không chứa chu trình với tổng trọng số âm Vì rằng nếu nh G có một chu trình H nh vậy thì xuất phát từ S, ta đi đến vH và sau đó đi vòng quanh chu trình H một số đủ lớn lần rồi đến

d ta sẽ thu đợc một đờng đi có trọng lợng đủ nhỏ   Vì vậy trong trờng hợp này đ-ờng đi ngắn nhất là không tồn tại

Tuy nhiên, việc giải bài toán tổng quát trên là nằm ngoài khuôn khổ bài tập lớn này, vì vậy chúng ta chỉ giải bài toán đặt ra trong trờng hợp các trọng số w(e)  0, G là đồ thị định hớng Ta xét một thuật toán đơn giản, hiệu quả để giải bài toán trong trờng hợp này

2 Giải bài toán với trọng số không âm – thuật toán Dijkstra. thuật toán Dijkstra.

Trang 2

Dijkstra là ngời đầu tiên đề nghị thuật toán hữu hiệu giải bài toán tìm đờng đi ngắn nhất từ s tới d Phơng pháp này đơc xây dựng dựa trên cơ sở dán các nhãn tạm thời cho các đỉnh Nhãn của mỗi đỉnh cho biết cận trên của độ dài đờng đi ngắn nhất từ s đến

nó Các nhãn này đợc biến đổi theo các thủ tục lặp, mà ở mỗi bớc lặp lại có một nhãn tạm thời trở thành nhãn cố định Nếu nhãn của một đỉnh nào đó trở thành cố định thì

nó cho ta không phải là cận trên mà là độ dài của đờng đi ngắn nhất từ s đến nó Ta sẽ mô tả cụ thể thuật toán này

Thuật toán Dijkstra (w(e)  0):

Ký hiệu val(i), val(s) là nhãn của đỉnh v(i), s

B

ớc 1 Gán nhãn tạm thời cho tất cả các đỉnh Tất cả val của các đỉnh bằng  trừ val(s) = 0

B

ớc 2 Trong tất cả các đỉnh có nhãn tạm thời và khác  , tìm đỉnh có val nhỏ nhất Nếu tìm thấy, gọi đỉnh đó là vmin Nếu không tìm thấy thì không có đờng đi từ s

đến d, thoát

Thay đổi nhãn của vmin thành cố định Nếu vmin chính là d thì đã tìm đợc đờng đi ngắn nhất, độ dài đờng đi này chính là val(vmin), thoát

B

ớc 3 Với các đỉnh v(i) có nhãn tạm thời và kề với vmin (có cạnh hớng từ vmin

sang v(i), nói cách khác là w(vmin, v(i)) <  ) ta thay đổi val(i) theo qui tắc sau: val(i) := min{val(i), val(vmin) + w(vmin, v(i))}

Quay lại bớc 2

Phần chứng minh thuật toán này có thể thấy trong rất nhiều tài liệu nên để khỏi dài dòng, ta không cần nêu ra ở đây

II Chơng trình viết bằng ngôn ngữ Turbo Pascal.

1 Cách tổ chức ch ơng trình.

a Cấu trúc dữ liệu.

Trong chơng trình này những biến dùng để lu các trọng số của các cạnh chiếm rất nhiều bộ nhớ Ta sẽ dùng các biến kiểu real (6 bytes) để lu các trọng số Nếu ta lu trữ các trọng số vào ma trận kề thì chơng trình chỉ có thể xử lý cho số lợng đỉnh tối đa là xấp xỉ 100 đỉnh, một số lợng khá ít cho các bài toán thực tế Vì vậy việc chọn cấu trúc dữ liệu thích hợp cho chơng trình là hết sức quan trọng

Ta sẽ dùng cấu trúc danh sách kề để biểu diễn đồ thị Ta dùng một mảng một chiều

mà mỗi phần tử mảng là một danh sách móc nối Mỗi đỉnh của G có một danh sách t

-ơng ứng Các nút trong danh sách i biểu diễn các đỉnh lân cận của đỉnh v(i) Mỗi nút của danh sách thứ i gồm 3 trờng: index, long và link

 Trờng index cho biết chỉ số đỉnh kề với đỉnh v(i)

 Trờng long cho biết trọng số của cạnh nối từ nút v(i) đến nút có chỉ số index

 Trờng link trỏ tới nút tiếp theo trong danh sách hoặc bằng nil nếu đó là nút cuối cùng của danh sách

Ta thấy dùng cách biểu diễn đồ thị này tuy có phức tạp hơn dùng ma trận kề song chơng trình có thể dễ dàng giải quyết bài toán có số đỉnh số cạnh cỡ nghìn, đủ lớn cho nhiều ứng dụng thực tế

Ta khai báo trong chơng trình nh sau:

const

nmax=1001;

Trang 3

nn=1 nmax;

vertexPtr=^vertexNode;

vertexNode=record

index: word;

long: real;

link: vertexPtr;

end;

var

adj: array[nn] of vertexPtr;

Nmax là số đỉnh tối đa mà chơng trình có thể xử lý

Adj chính là mảng các danh sách kề

b Cấu trúc chơng trình.

Ta chia nhỏ chơng trình thành các module, mỗi module có chức năng riêng và do 1 hoặc 2 thành viên trong nhóm thiết kế Sau đây là cấu trúc chơng trình

program Find_The_Shortest_Way;

uses crt;

const declaration;

type declaration;

var declaration;

Procedure insert(i1, i2: integer; val: real);

Function check(a, b, n: integer): boolean;

Procedure inputFromFile;

Call insert, check;

Procedure showData;

Procedure inputFromKeyboard;

Call check;

Procedure dijkstra;

Procedure output;

Begin

Call inputFromFile, showData,

inputFromKeyBoard, Dijkstra, output, check;

end.

2 Chức năng của từng module.

Procedure insert(i1, i2: integer; val: real)

Thêm đỉnh v(i2) vào danh sách các đỉnh kề của v(i1), val là trọng số của cạnh (v(i1), v(i2))

Function check(a, b, n: integer): boolean;

Nếu 1 a, b n thì check trả về giá trị true, nếu không thì trả về false

Trang 4

Procedure inputFromFile;

Thủ tục này nhập các số liệu về đồ thị từ file text dijkstra.inp Ta đề cập luôn cấu trúc của file này Tất cả các số liệu về G, trừ s và d đợc nhập từ bàn phím, đều chỉ đợc ghi trong file trên

Đầu tiên thủ tục đọc số đỉnh của G vào biến toàn cục n có kiểu integer Trong file dữ liệu, n đợc ghi ngay sau dấu ‘:’ Xuống dòng, một dòng hớng dẫn Sau đó đến n dòng ghi chỉ số, tên của đỉnh ứng với chỉ số đó Các dòng tên đỉnh có thể ghi theo thứ

tự bất kỳ Biến mảng name toàn cục chứa tên của các đỉnh, mỗi tên có không quá 15 ký

tự Dành tiếp một dòng cho hớng dẫn Mỗi dòng tiếp theo cho thông tin về một cạnh của đồ thị Mỗi dòng gồm 2 chỉ số đỉnh i1, i2 và trọng số của cạnh hớng từ v(i1) đến v(i2) Trọng số là số thực để có thể áp dụng tốt hơn số nguyên cho các bài toán thực tế Kết thúc file

Procedure showData;

Thủ tục này hiển thị một phần thông tin về G ra màn hình nhằm giúp ngời sử dụng kiểm tra thêm về tính đúng đắn của dữ liệu (chỉ dùng cho những đồ thị bé) Các thông tin đợc hiển thị bao gồm: số đỉnh, số cạnh, tên các đỉnh, danh sách kề (không có thông tin về độ lớn của các cạnh)

Procedure inputFromKeyboard;

Thủ tục này lấy các chỉ số của đỉnh nguồn, đỉnh đích do ngời sử dụng nhập từ bàn phím đa vào 2 biến toàn cục nguyên: source và dest Nó đơc chơng trình chính sử dụng kết hợp với hàm check tạo nên vòng lặp sử dụng chơng trình Khi ngời dùng nhập vào một số không nằm trong [1, n] thì chơng trình kết thúc ngay

Procedure dijkstra;

Đây là thủ tục chính, hạt nhân của chơng trình Chúng ta sẽ mô tả kỹ hơn về thủ tục này

Thủ tục dùng các biến mảng val, dad, mark, adj Chúng ta đã biết adj là mảng danh sách kề lu trữ thông tin về các cạnh của đồ thị có hớng G, còn val (viết tắt của value) lu nhãn của các đỉnh Ta định nghĩa hằng maxreal = 1e38 đủ lớn để đại diện cho đại lợng

 Mảng mark cho biết trạng thái nhãn của các đỉnh Mark[i] bằng 0 hoặc 1 cho biết nhãn đỉnh v(i) là tạm thời hay cố định Còn mảng dad dùng để lu trữ thông tin về đờng

đi để sau khi tìm đợc đờng đi ngắn nhất, ta sẽ dùng nó để tìm lại đờng đi từ s đến d Trong các bớc lặp, nếu val[i] đợc thay đổi, dad[i] sẽ chứa đỉnh đứng ngay trớc v(i) trong đờng đi đã tìm đợc ở thời điểm đó Nếu nhãn của v(i) là cố định, dad[i] chính là chỉ số của đỉnh đứng ngay trớc đỉnh i trong đờng đi ngắn nhất từ s đến v(i)

Biến imin, vmin là chỉ số và giá trị nhãn của đỉnh vmin ta đã đề cập trong b ớc 2 của thuật toán Biến toàn cục found kiểu boolean cho biết đã gặp đỉnh đích và gán nhãn cố

định cho nó hay cha

Thực tế là có nhiều cách tổ chức lu trữ cho các biến adj, name, dad, mark, val để tiết kiệm bộ nhớ hơn nữa, song với chơng trình bài tập lớn này ta thấy đó là điều không cần thiết lắm vì nó làm tăng độ phức tạp của chơng trình lên mà hiệu quả không tăng nhiều Do vậy ta vẫn chọn kiểu mảng một chiều đơn giản cho các biến trên

Vì thủ tục đơc thiết kế rất trung thành với ý tởng thuật toán đề ra và đoạn mã cũng ngắn, dễ hiểu nên để cho hiệu quả, nhanh chóng chúng ta sẽ bỏ qua phần thiết kế thủ tục bằng ngôn ngữ tựa Pascal

Trang 5

Procedure output;

Thủ tục này xuất kết quả ra file text dijkstra.out, đồng thời đa kết quả ra màn hình

để ngời sử dụng dễ theo dõi đối với các đồ thị cỡ nhỏ Nếu nh tìm đợc đờng đi, thủ tục này cũng kiêm luôn chức năng dò lại đờng đi, lu vào mảng way

3 Văn bản ch ơng trình.

Xin xem chơng trình dijkstra.pas trong đĩa kèm theo

program Find_The_Shortest_Way;

uses crt;

const

nmax=1001;

maxreal=1e38;

fi='dijkstra.inp';

fo='dijkstra.out';

type

nn=1 nmax;

vertexPtr=^vertexNode;

vertexNode=record

index: word;

long: real;

link: vertexPtr;

end;

var

f: text;

n, e, start, dest: integer;

name: array[nn] of string[15];

val: array[nn] of real;

dad, way: array[nn] of word;

mark: array[nn] of byte;

adj: array[nn] of vertexPtr;

found: boolean;

Procedure insert(i1, i2: integer; val: real);

var

v: vertexPtr;

begin

new(v);

v^.index:=i2;

v^.long:=val;

v^.link:=adj[i1];

adj[i1]:=v;

end;

Trang 6

Function check(a, b, n: integer): boolean;

begin

check:=(a>=1)and(a<=n)and(b>=1)and(b<=n);

end;

Procedure inputFromFile;

var

s: string;

ch: char;

i, j, k, i1, i2: integer;

val: real;

begin

assign(f, fi); reset(f);

ch:=#0;

repeat

read(f, ch);

until eof(f) or (ch=':');

readln(f, n);

if eof(f) or not check(n, 1, nmax) then halt; readln(f);

for i:=1 to n do

begin

read(f, k);

readln(f, s);

while (s[1]=' ') and (s<>'') do delete(s, 1, 1); name[k]:=s;

adj[i]:=nil;

end;

readln(f);

e:=0;

while not eof(f) do

begin

readln(f, i1, i2, val);

if (i1>=1)and(i1<=n)and(i2>=1)and(i2<=n) then

begin

insert(i1, i2, val);

inc(e);

end;

end;

close(f);

end;

Procedure showData;

var

s: string;

i: integer;

v: vertexPtr;

begin

writeln(n, ' vertices, ', e, ' edges.');

for i:=1 to n do

Trang 7

begin

s:=name[i];

while length(s)<15 do s:=s+' ';

write(i: 4, s: 16);

end;

writeln; writeln;

writeln('Adj list:');

for i:=1 to n do

begin

write(i: 4, ' ');

v:=adj[i];

while v<>nil do

begin

write(v^.index: 4);

v:=v^.link;

end;

writeln;

end;

writeln;

end;

Procedure inputFromKeyboard;

begin

writeln;

writeln('*******************************'); writeln('Input data please (0 for quit).'); write('Index of source vertex: ');

readln(start);

if not check(start, 1, n) then exit;

write('Index of dest vertex: ');

readln(dest);

writeln;

end;

Procedure dijkstra;

var

i, j, k, imin: integer;

vmin: real;

finish: boolean;

v: vertexPtr;

begin

found:=false;

fillchar(dad, 2*n, 0);

fillchar(mark, n, 0);

for i:=1 to n do val[i]:=maxreal;

val[start]:=0;

while true do

begin

vmin:=maxreal;

for i:=1 to n do

Trang 8

if (val[i]<vmin) and (mark[i]=0) then

begin

vmin:=val[i];

imin:=i;

end;

if (vmin=maxreal) or (imin=dest) then break;

mark[imin]:=1;

v:=adj[imin];

while v<>nil do

begin

with v^ do

if (mark[index]=0) and (val[index] > val[imin]+long) then

begin

val[index]:=val[imin]+long;

dad[index]:=imin;

end;

v:=v^.link;

end;

end; {while true}

if imin=dest then found:=true;

end;

Procedure output;

var

m, i, k: integer;

begin

assign(f, fo); rewrite(f);

if not found then

begin

writeln('Can not go from ', name[start], ' to ', name[dest]);

writeln(f, 'Can not go from ', name[start], ' to ', name[dest]);

close(f);

exit;

end;

k:=dest;

m:=0;

repeat

inc(m);

way[m]:=k;

k:=dad[k];

until k=0;

writeln('The shortest way from ', name[way[m]], ' to ', name[way[1]], ' is:');

writeln(f, 'The shortest way from ', name[way[m]], ' to ', name[way[1]], ' is:');

for i:=m downto 1 do

begin

writeln(way[i]: 4, ' ', name[way[i]]);

writeln(f, way[i]: 4, ' ', name[way[i]]);

end;

writeln;

Trang 9

writeln(f);

writeln('Total length: ', val[dest]: 10);

writeln(f, 'Total length: ', val[dest]: 10);

close(f);

end;

Begin

clrscr;

inputFromFile;

showData;

repeat

inputFromKeyBoard;

if not check(start, dest, n) then break;

dijkstra;

output;

until false;

end.

4 Kiểm tra ch ơng trình.

File dijkstra.inp đã chứa sẵn thông tin về đồ thị mẫu sau:

Kết quả trên màn hình khi chạy chơng trình:

7 vertices, 14 edges.

1 Ha Noi 2 Paris 3 Tokyo 4 London

5 Hong Kong 6 Sai Gon 7 New York

Adj list:

1 6 7 2

Trang 10

2 7 3

3 7 4

4 7

5 4

6 7 5

7 6 5 4

*******************************

Input data please (0 for quit).

Index of source vertex:

Chọn đỉnh đầu là 1, đỉnh đích là 4 ta đợc:

*******************************

Input data please (0 for quit).

Index of source vertex: 1

Index of dest vertex: 4

The shortest way from Ha Noi to London is:

1 Ha Noi

2 Paris

3 Tokyo

7 New York

6 Sai Gon

5 Hong Kong

4 London

Total length: 6.010E+01

*******************************

Input data please (0 for quit).

Index of source vertex:

Chọn đỉnh đầu là 5, đỉnh đích là 1 ta đợc:

*******************************

Input data please (0 for quit).

Index of source vertex: 5

Index of dest vertex: 1

Can not go from Hong Kong to Ha Noi

*******************************

Input data please (0 for quit).

Index of source vertex: 0

Trang 11

(*******************************************************)

Ngày đăng: 09/05/2016, 22:30

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w