1. Trang chủ
  2. » Giáo án - Bài giảng

Tài liệu ôn thi HSG

6 1,1K 34
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tài Liệu Ôn Thi HSG
Trường học Trường Đại Học Công Nghệ Thông Tin
Chuyên ngành Công Nghệ Thông Tin
Thể loại Tài liệu
Định dạng
Số trang 6
Dung lượng 49,5 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Đánh dấu phần tử đợc chọn1- ý tởngchung Kỹ thuật đánh dấu phần tử là một trong những kỹ thuật nhằm giúp cho ngời lập trình tạo đợc những thuật toán đơn giản để giải quyết vấn đề đặt ra..

Trang 1

Đánh dấu phần tử đợc chọn

1- ý tởngchung

Kỹ thuật đánh dấu phần tử là một trong những kỹ thuật nhằm giúp cho ngời lập trình tạo đợc những thuật toán đơn giản để giải quyết vấn đề đặt ra.

Để đánh dấu phần tử đợc chọn, ta khai báo một mảng A gồm nhiều phần tử, với A[i]=true theo nghĩa i là phần tử đợc chọn, A[i]=false theo nghĩa i là phần tử không đợc chọn

2- ứng dụng PP đánh dấu trong bài toán sắp xếp dãy số

Sắp xếp dữ liệu đóng vai trò rất quan trọng trong xữ lý thông tin ý nghĩa thực tiễn của sắp xếp là nhằm dễ dàng tìm kiếm thông tin cần thiết

Bài toán: Cho một dãy số gồm N phần tử (1<=N<=32766) Các phần tử ai của dãy là các số nguyên dơng, đôi một khác nhau (1<=ai <=32766) Hãy sắp xếp dãy số tăng dần

Ta thờng sử dụng thuật giải sắp xếp đơn giản để giải quyết bài toán này nh sau:

For i:=1 to N-1 do

For j:=i+1 to N do

If a[i]<a[j] then

Begin t:=a[i];

a[i]:=a[j]

a[j]:=t;

End;

Chơng trình biểu diễn của thuật toán:

const fi='sap1.inp';

fo='sap1.out';

type mmc=array[1 32766] of integer;

var f:text;

i,j,n,t:integer;

a:^mmc; ti:longint;

begin

ti:=meml[0:$46c];

new(a);

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

readln(f,n);

for i:=1 to n do read(f,a^[i]);

close(f);

for i:=1 to n-1 do

for j:=i+1 to n do

if a^[i]>a^[j] then

begin

t:=a^[i]; a^[i]:=a^[j]; a^[j]:=t;

end;

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

writeln(f,n);

for i:=1 to n do write(f,a^[i],' ');

close(f);

dispose(a);

writeln('Thoi gian thu hien ',(meml[0:$46c]-ti)/18.21:8:5);

Trang 2

end.

Khi N bé, thuật toán trên là chấp nhận đợc Tuy nhiên, trong nhiều trờng hợp N lớn, chẳng hạn N=32766 phần tử, khi đó độ phức tạp của thuật toán là O(N2) máy sẽ thực hiện trong rất nhiều thời gian mới sắp xếp đợc dãy số (với N=20000, thời gian thực hiện khoảng

14 giây)

Để giải quyết đợc bài toán này khi N lớn trong một khoảng thời gian rất nhỏ, ta sử dụng kỹ thuật đánh dấu phần tử

Ta cần chú ý đến một giả thiết quan trọng trong bài toán đặt ra là “các phần tử đôi một khác nhau”, nghĩa là trong dãy không có phần tử nào trùng nhau Đối với bài toán sắp xếp có phần tử trùng nhau ta không thể sử dụng phơng pháp này

Phơng pháp:

Dữ liệu:

Sử dụng một mảng A gồm 32766 phần tử, các phần tử có kiểu boolean

ý nghĩa:

A[i]=true có nghĩa i là phần tử có trong dãy, A[i]=false có nghĩa i là phần tử không

có trong dãy

Thuật toán:

+ Khởi động mọi giá trị của A[] là False {Giống nh giả sử ban đầu mọi phần tử đều không thuộc dãy số}

+ Đọc từng phần tử của dãy số, giả sử số thứ j của dãy là X, ta đánh dấu phần tử A[X]=true {Xác nhận số X thuộc dãy số} Thực hiện đánh dấu cho đến khi đọc hết dãy số Khi đó ta thu đợc một mảng A[] trong đó A[i]=true tại các chỉ số i có giá trị bằng giá trị các phần tử trong dãy số

+ Duyệt từ đầu mảng đến cuối mảng, nếu vị trí vào có giá trị True thì ta xuất chỉ số

đó ra Kết quả ta đợc một dãy số đợc sắp xếp tăng dần

Chơng trình mẫu:

const fi='sap1.inp';

fo='sap2.out';

type mmcb=array[1 32766] of boolean;

var f:text;

n:word;

b:mmcb;

ti:longint;

procedure doc;

var i,x:word;

begin

fillchar(b,sizeof(b),false);

assign(f,fi);

reset(f);

readln(f,n);

for i:=1 to n do

begin

read(f,x);

b[x]:=true;

end;

close(f);

assign(f,fo);

Trang 3

writeln(f,n);

for i:=1 to 32766 do

if b[i]=true then write(f,i,' ');

end;

begin

ti:=meml[0:$46c];

doc;

writeln('TG=',(meml[0:$46c]-ti)/18.21:8:4);

readln;

end.

Nhận xét:

Khi N=20000 chơng trình thực hiện trong 0.05giây Chơng trình này chạy nhanh gấp 280 lần so với chơng trình đã viết theo thuật toán đơn giản trên.

Rõ ràng, kỹ thuật đánh dấu phần tử có ý nghĩa rất quan trọng trong việc giảm thời gian thực hiện chơng trình

3-ứng dụng PP đánh dấu trong bài toán lọc dữ liệu

Lọc dữ liệu là một vấn đề có ý nghĩa to lớn trong xử lý thông tin ý nghĩa thực tiễn của lọc dữ liệu là nhằm loại bỏ các dữ liệu d thừa, không cần thiết, từ đó dễ dàng thu đợc thông tin cần tìm

Bài toán: Cho một dãy số gồm N phần tử (1<=N<=32766), trong đó các phần tử có kiểu nguyên nằm trong [1 32766] Hãy trích ra từ dãy số trên một tập con gồm nhiều phần

tử nhất sao cho các phần tử đôi một khác nhau

Ta thờng giải quyết bài toán trên theo thuật toán đơn giản nh sau:

+ Dùng một mảng B[] để lu các giá trị tìm đợc

+ Đọc từng phần tử của dãy số đã cho, giả sử số đọc đợc là X Kiểm tra xem X đã có trong B[] hay cha

+ Nếu cha có trong B[] thì đặt vào cuối cùng của B[]

Khi N bé, thuật toán trên có thể chấp nhận đợc Tuy nhiên, trong nhiều trờng hợp N rất lớn, chẳng hạn N=32766 phần tử, khi đó độ phức tạp của thuật toán là O(N2) máy sẽ thực hiện trong rất nhiều thời gian để lấy từng phần tử trong dãy để so sánh với các phần tử trong tập B[]

Để giải quyết đợc bài toán này khi N lớn trong một khoảng thời gian rất nhỏ, ta sử dụng kỹ thuật đánh dấu phần tử

Phơng pháp:

Dữ liệu:

Sử dụng một mảng B gồm 32766 phần tử, các phần tử có kiểu boolean

ý nghĩa:

B[i]=true có nghĩa i là phần tử ta sẽ chọn, B[i]=false có nghĩa i là phần tử ta không chọn

Thuật toán:

+ Khởi động mọi giá trị của B[] là False {Giống nh giả sử ban đầu ta cha chọn phần

tử nào cả}

+ Đọc từng phần tử của dãy số, giả sử số thứ j của dãy là X, ta đánh dấu phần tử B[X]=true {Xác nhận số X đợc chọn} Thực hiện đánh dấu cho đến khi đọc hết dãy số Khi

đó ta thu đợc một mảng B[] trong đó B[i]=true tại các chỉ số i mà ít nhất i xuất hiện một lần trong dãy đã cho

+ Duyệt từ đầu mảng đến cuối mảng B[], nếu vị trí nào có giá trị True thì ta xuất chỉ

số đó ra Kết quả ta đợc một tập các phần tử cần tìm

Chơng trình mẫu:

Trang 4

const fi='tc.in1';

fo='tc.ou4';

nn=60000;

var n,a:word;

f:text;

k:array[1 nn] of boolean;

procedure doctep;

var i:word;

begin

assign(f,fi);

reset(f);

readln(f,n);

for i:=1 to n do

begin

read(f,a);

k[a]:=true;

end;

close(f);

end;

procedure xulivaxuat;

var i,d:word;

begin

assign(f,fo);

rewrite(f);

d:=0;

for i:=1 to nn do

if k[i]=true then d:=d+1;

writeln(f,d);

for i:=1 to nn do

if k[i]=true then write(f,' ',i);

close(f);

end;

BEGIN

doctep;

xulivaxuat;

END.

Nhận xét: Chơng trình này chạy nhanh gấp khoảng 300 lần so với chơng trình đã viết theo

thuật toán đơn giản trên

4-ứng dụng PP đánh dấu trong bài toán tìm giao của hai tập hợp

Xác định giao của hai tập hợp là một bài toán quan trọng trong toán học Trong thực tiễn, phép giao nhằm giúp ta xác định đợc nhóm thông tin chung nhất của nhiều nhóm thông tin

Bài toán:

Cho 2 tệp văn bản TEP1.INP và TEP2.INP chứa N số tự nhiên trong khoảng 1 M có thể trùng nhau Hãy tạo TEP3.OUT chứa các số có mặt trong cả hai tệp TEP1.INP và TEP2.INP sao cho các số đôi một khác nhau

Trang 5

DLV DLR Dòng 1: Số N (1<=N<=32766)

Dòng 2: N số ai (1<=ai<=M<=32766)

Dòng 1 chứa các số tìm đợc

Ví dụ

7

5 7 1 3 5 2 7

6

3 5 1 2 1 19

1 3 2 5

Ta thờng giải quyết bài toán trên theo thuật toán đơn giản nh sau:

+ Dùng mảng A[] để lu các số trong tệp 1

+ Dùng mảng B[] để lu các số trong tệp 2

+ Lấy từng phần tử Xi trong A[], so sánh với lần lợt từng phần tử Yj trong B[] Nếu Xi

có trong B[] thì đem Xi đặt vào mảng C[]

+ Lấy từng phần tử Yj trong B[], so sánh với lần lợt từng phần tử Zk trong C[] Nếu Yj

có trong C[] thì đem Yj đặt vào mảng D[]

+ Xuất mảng D, ta thu đợc tập giao của hai tệp

Khi N bé, thuật toán trên có thể chấp nhận đợc Tuy nhiên, trong nhiều trờng hợp N rất lớn, chẳng hạn N=32766 phần tử, khi đó độ phức tạp của thuật toán là O(2N2) máy sẽ thực hiện trong rất nhiều thời gian để lấy từng phần tử trong A[] để so sánh với các phần tử trong B[]

Để giải quyết đợc bài toán này khi N lớn trong một khoảng thời gian rất nhỏ, ta sử dụng kỹ thuật đánh dấu phần tử nh sau:

Phơng pháp:

Dữ liệu:

Sử dụng hai mảng A và B gồm 32766 phần tử, các phần tử có kiểu boolean

ý nghĩa:

A[i]=true có nghĩa i là phần tử thuộc tệp 1, A[i]=false có nghĩa i là phần tử không thuộc tệp 1

B[i]=true có nghĩa i là phần tử thuộc tệp 2, B[i]=false có nghĩa i là phần tử không thuộc tệp 2

Thuật toán:

+ Khởi động mọi giá trị của A[] và B[] là False

+ Đọc từng phần tử của tệp 1, giả sử số đọc đợc của dãy là X, ta đánh dấu phần tử A[X]=true {Xác nhận số X thuộc tệp 1} Thực hiện đọc và đánh dấu cho đến khi đọc hết tệp 1

Khi đó ta thu đợc một mảng A[] trong đó A[i]=true tại các chỉ số i mà ít nhất i xuất hiện một lần trong tệp 1

+ Đọc từng phần tử của tệp 2, giả sử số đọc đợc của dãy là Y, ta đánh dấu phần tử B[Y]=true {Xác nhận số Y thuộc tệp 2} Thực hiện đọc và đánh dấu cho đến khi đọc hết tệp 2

Khi đó ta thu đợc một mảng B[] trong đó B[i]=true tại các chỉ số i mà ít nhất i xuất hiện một lần trong tệp 2

+ Duyệt từ đầu mảng đến cuối mảng A[] B[], nếu tại vị trí nào mà A[i] và B[i] có giá trị True thì ta xuất chỉ số đó ra Kết quả ta đợc một tập các phần tử cần tìm

Chơng trình mẫu:

const f1='tep1.inp';

f2='tep2.inp';

f3='tep3.out';

type mmc=array[1 32767] of boolean;

var n,i,j,a:longint;

k:mmc;

Trang 6

procedure doctep;

begin

assign(f,f1);

reset(f);

readln(f,n);

for i:=1 to n do

begin

read(f,a);

k[a]:=true;

end;

close(f);

end;

procedure xulivaxuat;

begin

assign(fi,f3);

rewrite(fi);

assign(f,f2);

reset(f);

readln(f,n);

for i:=1 to n do

begin

read(f,a);

if k[a]=true then

begin

write(fi,' ',a);

k[a]:=false;

end;

end;

close(f);

close(fi);

end;

BEGIN

doctep;

xulivaxuat;

end.

Nhận xét: Chơng trình này chạy nhanh gấp 400 lần so với chơng trình đã viết theo thuật toán

đơn giản trên

Ngày đăng: 01/08/2013, 05:41

TỪ KHÓA LIÊN QUAN

w