Kỹ thuật dùng Bộ nhớ ảo trong các bài toán có số liệu lớnNguyễn Trung Hải I.. Vấn đềmở rộng bộ nhớ của Pascal bằng VM được đặt ra và rất đáng lưu tâm.ở đây, tôi xin trình bày cách sử dụn
Trang 1Kỹ thuật dùng Bộ nhớ ảo trong các bài toán có số liệu lớn
Nguyễn Trung Hải
I Mở đầu:'Bộ nhớ ảó (Virtual Memory − VM) là thuật ngữ chỉ việc hệ điều hànhđã tự
nâng cấp dung lượng bộ nhớ thực (RAM) bằng cách sử dụng mộtkhông gian đĩa cứng làm nơi lưu trữ dữ liệu tạm thời lúc đang xửlí Nhờ đó, tránh được việc đứng máy Dù sao, con RAM của máy tínhcòn lớn đến hàng trăm Mb, trong khi con 'RAM' của Pascal chúng ta chỉcó 64Kb, nghĩa là chứa khoảng 32 000 phần tử là tối đa Vậy thì làmsao giải quyết những bài toán yêu cầu tổ chức dữ liệu lớn? Vấn đềmở rộng bộ nhớ của Pascal bằng VM được đặt ra và rất đáng lưu tâm.ở đây, tôi xin trình bày cách sử dụng VM bằng kiểu file, một kiểu dữliệu quen thuộc, sau khi đã lĩnh hội được, các bạn có thể sáng tạocho mình một phương pháp tối ưu
II Bài toán:
Ta hãy xétlại bài toán xếp ba lô quen thuộc: Cho n vật có thể tích A[i] và giátrị B[i] Hãy liệt kê ra chỉ số của 1 số vật sao cho tổng thể tích củachúng không vượt V cho trước và tổng giá trị là lớn nhất
Phương phápquen thuộc mà chúng ta được học là quy hoạch động:
1 Lập bảngF[i,j] cho biết tổng giá trị max của i vật được chọn từ 1 đến i vàgiá trị không
vượt quá j
2 Lập hàmquy hoạch động tính F[i,j] theo F[i-1,ji] (ji=1 n) để tìm F[n,v]
3 Truy xuấtngược các chỉ số các vật được chọn
Vấn đề là:Với V ≤ 10000, n ≤ 10000 (giới hạn thêm ) thì sẽ không giải quyết theo phương pháp bình thường được vì bảngF sẽ có 108 phần tử (quá lớn so với 32000) Vì thế ta sẽchia bảng thành n hàng, mỗi hàng V số, và vì tính giá trị hàng i chỉphụ thuộc vào hàng i-1 nên ta sẽ xử lí từng hàng một bằng bảng mộtchiều duy nhất, xong hàng nàoghi lại hàng đó ra file, để dành sau truy xuất Cụ thể, ở mỗi bướctính giá trị hàng i:
+ F1[1 V] làbảng lưu các giá trị hàng i-1, F2[1 V] là bảng lưu giá trị hàng i (cầntính), do
V ≤ 10000nên giá trị F1[i],F2[i] đủ lớn để xử lí được
+ Tiến hànhđọc giá trị A[i]; B[i]
+ Lập hàmtính F2[j] theo F1[jj-1] với tham số A[i], B[i] (j,jj=1 n)
+ GhiF2[1 v] vào file tạm, gán F1:=F2 cho lần xử lý kế tiếp
Như vậyfile tạm sẽ chứa n x v số, tương ứng với giá trị bảng F, nhưng tađã tích hợp nó thành 2 mảng một chiều F1, F2 duy nhất với VM là filechứa tạm
Tuy nhiên,việc file truy xuất ngược yêu cầu đọc file từ dưới lên, trong khifile text chỉ cho đọc tuần tự từ trên xuống Do đó, Chúng ta phải thựchiện 1 'thao tác nhỏ' ghi ngược file
để tạm thời truy xuất
Procedureinnguoc;
Begin
{Mở filecần ghi ngược}
For i:=ndownto 1 do
Trang 2Begin {Mởfile tạm để đọc, xuống dòng n-1 lần, đọc dòng hiện thời của con trỏvà ghi vào file ngược, đóng file đọc}
End; End;
Như vậyfile tạm ban đầu sẽ được mở ra đóng lại n lần Vấn đề còn lạixin dành cho bạn đọc, tất nhiên việc truy xuất cũng dựa vào quan hệhai dòng liên tiếp nên ta dùng lại 2 mảng F1,F2 ban nãy để giải quyết.Lưu ý hàng n của bảng F giờ đã thành hàng i của file ngược, nên việctruy xuất các chỉ số có ngược lại một chút
Chương trình:(xem phụ lục 1)
Như thế, kĩthuật dùng VM giống như việc mã hoá vậy:
- DùngF1, F2 giả làm các hàng liên tiếp để ghi bảng giá trị vào file tạm
- In ngược(nếu cách làm bắt buộc) rồi lại dùng F1, F2 để xuất kết quả ra
VM đã chophép ta sử dụng bộ nhớ gấp 3125 lần (đối với bài toán trên), mộtcon số không nhỏ phải không các bạn? Nhưng phương pháp này cũng bộclộ 2 nhược điểm: chỉ áp dụng cho các phép tính tuần tự, tăng độphức tạp chương trình nên thời gian chạy lâu
Vì thế, nóđặc biệt thích hợp cho quy hoạchđộng và đồ thị, nhiều lúc đây còn là phương
án duy nhất vượtqua rào cản về dung lượng Việc cân nhắc giữa độ phức tạp và độlớn bộ nhớ là việc đáng suy ngẫm, để cải thiện tối đa bài toán
Ví dụ: Dướiđây cho thấy việc sử dụng khéo léo VM để tối ưu hoá bài toán:
Cho bảng sốtam giác như hình vẽ Mỗi bước đi chỉ đi thẳng xuống bên phải haybên trái
số đó Hãy tìm lộ trình đi từ đỉnh xuống đáy sao cho tổngcác số trên đường đi là lớn nhất
Input: Dòng1 ghi số N (1 ≤ N ≤ 10000),dòng i+1 (1 ≤ i ≤ N)ghi i số của bảng tam giác
(tổng các số trên mỗi đường đi ≤ 50000)
Output: Dòng1 ghi tổng lớn nhất tìm được Dòng i+1 (1 ≤ i ≤ N)ghi chỉ số các số nằm
trên lộ trình
Vì bướcđi đến hàng i phải từ hàng i-1 đến nên ta có thể dùng 2 mảng F1,F2để giải quyết như trên Có điều giá trị F[ij] chỉ phụ thuộcF[i-1,j-1] và F[i-1,j] nên việc xuất kết quả có đơn giản hơn, tuy nhiênvì kết quả là ngược mà yêu cầu phải ghi lộ trình xuôi nên ta phảidùng VM ghi ngược file kết quả để được lộ trình chính xác
Chương trình(Xem phụ lục 2)
III Thay lờikết: Tuỳ vào bài toán mà VM có những kĩ thuật riêng Do đó nó cònphụ
thuộc vào kĩ năng mỗi người Mong các bạn sáng tạo ra nhiều phương pháp dùng VM độc chiêu hơn dành cho mình Còn bài tập,chẳng cần đâu xa, các bạn hãy nâng giới hạn những bài mình đã từnglàm rồi dùng phương pháp quy hoạch trên để giải quyết xem sao Chúccác bạn thành công!
Phụ lục I:
ProgramXepbalo;
var f1,f2: array[0 10000] of 0 50000;
a:array[1 10000] of 0 50000;
fi, fo:text;
n,v,i,j,b,t;0 100000;
ProcedureInit;
Begin
assign(fi,′balo.inp′);reset(fi); assign(fo,′tam.inp′); rewrite(fo);
Trang 3readln(fi,n,v);
Fori:=1 to n do
begin
readln(fi,a[i],b);
for j:=1 to v do
begin
If (j>=a[i]) and (f1[j-a[i]) +b> f1[j]) then f2[j]:=f1[j-a[i]]+b
Else F2[j]:=f1[j];
write(fo,f2[j],′′);
end;
f1:=f2;
writeln(fo);
End;
close(fi);close(fo);
End;
Procedureinnguoc;
begin
assign(fi,′tam.inp′);reset(fi);
forj:=1 to i-1 do readln(fi);
forj:=1 to v do
begin
read(fi,t); write(fo,t,′′);
end;
writeln(fo);close(fi);
End;
Procedurexuat;
var max,maxi, a1,a2: 0 100000;
Begin
assign(fi,′kq.txt′);reset(fi);
assign(fo,′balo.out′);rewrite(fo);
max:=f1[1];maxi:=1;
for i:=2 tov do
if f1[i]> max then begin max:=f1[i]; maxi:=i ; end;
write(fo,max); a1:=max; readln(fi);
for i:=n downto 1 do
begin
for j:=1 to maxi do read(fi,f2[j]); readln(fi);
If f2[j]<> a1 then begin write(fo,i,′′); maxi:=maxi-a[i];a1:=f2[maxi]; end; end;
close(fo);
End;
BEGIN
Trang 4init;
innguoc;
xuat;
END
Phụ lụcII
ProcedureTringle;
var f1,f2,a:array[0 10000] of 0 50000;
fi,fo: text;
t,n,v,i,j,b:0 100000;
Functiongetmax(x,y: word): word;
begin
ifx>=y then getmax:=x else getmax:=y;
end;
ProcedureInit;
Begin
assign(fi,′triang.inp′);reset(fi); assign(fo,′tam.inp′); rewrite(fo); readln(fi,n);
fori:=1 to n do
begin
for j:=1 to i do
begin
readln(fi,f2[j]) f2[j]:=f2[j]+getmax(f1[j],f1[j-1]);
write(fo,f2[j],′′);
end;
close(fi); close(fo);
End;
Procedureinnguoc;
var t:0 10000;
begin
assign(fo,′kq.txt′);rewrite(fi);
fori:=n downto 1 do
begin
assign(fi,′tam.inp′); reset(fi);
for j:=1 to i do readln(fi);;
for j:=1 to i do begin read(fi,t); write(fo,t,′′); end;
writeln(fo); close(fi);
end; close(fo);
end;
Trang 5Procedurexuat;
var max, maxi, a1,a2,t1,t2: 0 100000;
begin
assign(fi,′kq.inp′);reset(fi); assign(fo,′triang.out′); rewrite(fo); max:=f1[1];maxi=1;
fori:=2 to n do if f1[i] > =max then
begin
max:=f1[i]; maxi:=i;
end;
write(fo,max);
fori:=n downto 1 do
begin
a1:=0; a2:=0; t1:=0; t2:=0;
for j:=1 to maxi-1 do
begin read(fi,a1); t1:=j;end; read(fi,a2); readln(fi);
t2:=t1+1;
if a1>a2 then begin a[i]:=a1; maxi:=t1; end
else begin a[i]:=a2;maxi:=t2; end;
end;
for i:=1 ton do writeln(fo,a[i]); close(fi); close(fo);
end;
BEGIN
init;innguoc; xuat;
END