Tải bản đầy đủ (.doc) (7 trang)

Tài liệu ôn thi HSG

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

Phơng pháp đánh dấu phần tử đợc chọn
Đá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ử a
i
của dãy là
các số nguyên dơng, đôi một khác nhau (1<=a
i
<=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;
CTT Media
Phơng pháp đánh dấu phần tử đợc chọn
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);
readln;
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(N
2
) 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
CTT Media
Phơng pháp đánh dấu phần tử đợc chọn
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);
rewrite(f);
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(N
2
) 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[].
CTT Media
Phơng pháp đánh dấu phần tử đợc chọn
Để 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:
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
CTT Media
Phơng pháp đánh dấu phần tử đợc chọn
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.
DLV DLR
Dòng 1: Số N(1<=N<=32766)
Dòng 2: N số a

i
(1<=a
i
<=M<=32766)
Dòng 1 chứa các số tìm đợc
Ví dụ
TEP1.INP TEP2.INP TEP3.OUT
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ử X
i
trong A[], so sánh với lần lợt từng phần tử Y
j
trong B[]. Nếu X
i
có trong B[] thì đem X
i
đặt vào mảng C[].
+ Lấy từng phần tử Y
j
trong B[], so sánh với lần lợt từng phần tử Z
k
trong C[]. Nếu Y
j

có trong C[] thì đem Y
j
đặ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(2N
2
) 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:
CTT Media

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×