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

Giải bài toán Quy hoạch động kinh điển

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

Một số bài toán quy hoạch động
Đỗ Quang Tiến
Khi gặp một bài toán tin có yêu cầu tìm kết quả tốiưu về một hay nhiều tính chất nào đấy,
hẳn không ít người nghĩ ngay đến sử dụnggiải thuật quy hoạch động để giải bài toán. Tại
sao lại vậy Bởi vì quy hoạchđộng thường có độ phức tạp tính toán không cao nghĩa là
chương trình sẽ chạycho ra kết quả đúng trong thời gian ngắn cho phép. Tuy nhiên, không
phải bàitoán với yêu cầu tối ưu nào cũng có thể giải bằng quy hoạch động, mặt khác
cũngcó không ít bài toán đúng là có thể giải bằng quy hoạch động nhưng việc pháthiện và
áp dụng phương pháp này để giải là không đơn giản.
Việc phát hiện cũng như áp dụng quy hoạch động đểgiải bài toán phụ thuộc rất lớn vào khả
năng tư duy của bạn và đặc biệt lànhững kinh nghiệm mà bạn có.
Bài viết này sẽ không đề cập đến những khái niệm cơbản của quy hoạch động vì những
khái niệm này đã quá quen thuộc với mọi người.Bài viết chỉ dừng ở mức phân tích cụ thể
lời giải của một số bài toán khá hay,từ đó hy vọng ít nhiều giúp bạn có thêm một chút kinh
nghiệm trong lập trìnhgiải quyết các bài toán tin.
Trước tiên ta cùng xét một bài toán đã được sử dụngtrong kỳ thi Olympic Tin học sinh
viên Thủ đô năm 1998.
Bài 1. Giá trị biểu thức
Giả thiết X,Ylà hai số nguyên dương. Kí hiệu S
x
là tổng các chữ số trong dạngbiểu diễn cơ
số 10 của X, Dmax_y là chữ số lớn nhất và Dmin_y là chữ số nhỏnhất trong dạng biểu
diễn cơ số 10 của Y. Phép tính hai ngôi # với các toánhạng nguyên dương X,Y được định
nghĩa như sau:
( X#Y ) = S
x
*Dmax_y+ Dmin_y
Ví dụ:
(30#9) = 3*9 +9 = 36
(9#30) = 9*3 +0 = 27
Với X chotrước, một số biểu thức hợp lệ là:


(X#X)
((X#X)#X)
(X#(X#X)#(X#X)#X)
Ký hiệu kết quảbiểu thức là K. Cho X và K (0 < X,K < 10
9
-1) cần xác định sốít nhất m các
phép # để từ đó có thể xây dựng biểu thức thuộc dạng đang xét vớiX cho kết quả K và biểu
diễn của biểu thức.
Dữ liệu vào từfile văn bản BT.IN, dòng thứ nhất chứa X, dòng thứ hai chứa K.
Kết quả ra filevăn bản BT.OUT, dòng thứ nhất chứa m, dòng thứ hai chứa biểu thức.
Ví dụ:
BT.IN BT.OUT
718
81
3
((718 #(718 #718)) #718)
* * *
Thực ra đề bàinày cũng dễ hiểu không phức tạp lắm, bây giờ ta đi vào phân tích tìm lời
giảicho bài toán. Trước tiên nhận xét rằng cho 0 < X, K < 10
9
nên:
1 ≤ S
x
≤ 9*9
1 ≤ Dmax_x ≤ 9
0 ≤ Dmin_x ≤ 9
Từ đó 1 ≤ X#X ≤ 9*9*9+9 = 738, tức là biểu thức có một dấu # luôn mang giá trị trong
đoạn [1,738]. Suy rộnghơn thì giá trị của một biểu thức hợp lệ bất kỳ phải nằm trong đoạn
[1,738],đây chính là cốt lõi lời giải cho bài toán.
Rõ ràng ta chỉchấp nhận các giá trị K thoả mãn 1 ≤ K ≤ 738, nếu K nằm ngoài khoảng này

thì chắc chắn vô nghiệm.
Xét biểu thứcX#X có 1 dấu #, dễ thấy có 3 cách mở rộng biểu thức 1 dấu # này là:
- X#(X#X)
- (X#X)#X
- (X#X)#(X#X)
Giả sử B là mộtbiểu thức tạo bởi X và n dấu # thế thì có 3 cách mở rộng biểu thức này là:
- X#B (n+1dấu #)
- B#X (n+1dấu #)
- B#B (2*n+1dấu #)
Ta lập mảng mộtchiều L[1..738] trong đó L[i] cho biết số phép # ít nhất để từ X tạo ra kết
quảlà i, i=1..738. Dễ thấy mảng L mang tính truy hồi, lần ngược và khi làm cụ thểta thực
hiện như sau:
1. Khởi tạomảng A[1..738] := 0, mảng A đánh dấu các giá trị đã tạo được từ biểu thức có
Xvà #; khởi tạo mảng L nhận các giá trị Maxint.
2. Tìm T=X#X;A[T]:=1; L[T]:=1
3. Thực hiệnbước 3 cho đến khi mảng L không còn bị thay đổi:
For i:=1 to 738
Nếu A[i]=1 thì
t:=X#i;
Nếu L[t]>L[i]+1thì
L[t]:=L[i]+1;A[t]:=1;
t:=i#X;
Nếu L[t]>L[i]+1thì
L[t]:=L[i]+1;A[t]:=1;
t:=i#i;
Nếu L[t]>2*L[i]+1thì
L[t] :=2*L[i]+1;A[t]:=1;
L[K] cho số phép # tối thiểu của biểu thức cần tìm.
Để hoàn thiện chương trình tất nhiên phải thiết kếthêm mảng lưu trữ thế nào để sau này khi
in kết quả có thể đưa ra được cả vịtrí các dấu # và các dấu ngoặc của biểu thức. Trong

chương trình dưới đây, mảngPre và D có chức năng này. Sau đây là toàn văn chương trình
giải bài "Giátrị biểu thức":
{GiaTri Bieu Thuc - Qui hoach dong DQT }
uses crt;
const
nmax=738;
inp='bt.in';
out='bt.out';
var
f:text;
x,k :longint;
stop :boolean;
a,d :array[1..nmax]of byte;
l,pre:array[1..nmax]of integer;
procedure Nhap;
begin
assign(f,inp);
reset(f);
readln(f,x); readln(f,k);
close(f);
end;
function TinhGiaTri(x,y:longint):integer;
var i,k,dmax,dmin,sx:byte;
st:string;
c:integer;
begin
str(y,st);
dmax:=0; dmin:=9;
for i:=1 to length(st) do
begin

val(st[i],k,c);
if kthen dmin:=k;
if k>dmax then dmax:=k;
end;
str(x,st);
sx:=0;
for i:=1 to length(st) do
begin
val(st[i],k,c);
sx:=sx+k;
end;
TinhGiaTri:=sx*dmax+dmin;
end;
procedure TimBieuThuc;
var i,t,top:integer;
begin
fillchar(a,sizeof(a),0);
for i:=1 to 738 do L[i]:=maxint;
{---}

×