Giải bài toán Quy hoạch động kinh điển
Một số toán quy hoạch động Đỗ Quang Tiến Khi gặp tốn tin có u cầu tìm kết tốiưu hay nhiều tính chất đấy, hẳn khơng người nghĩ đến sử dụnggiải thuật quy hoạch động để giải toán Tại lại Bởi quy hoạchđộng thường có độ phức tạp tính tốn khơng cao nghĩa chương trình chạycho kết thời gian ngắn cho phép Tuy nhiên, khơng phải bàitốn với u cầu tối ưu giải quy hoạch động, mặt khác cũngcó khơng tốn giải quy hoạch động việc pháthiện áp dụng phương pháp để giải không đơn giản Việc phát áp dụng quy hoạch động đểgiải toán phụ thuộc lớn vào khả tư bạn đặc biệt lànhững kinh nghiệm mà bạn có Bài viết khơng đề cập đến khái niệm cơbản quy hoạch động khái niệm quen thuộc với người.Bài viết dừng mức phân tích cụ thể lời giải số toán hay,từ hy vọng nhiều giúp bạn có thêm chút kinh nghiệm lập trìnhgiải tốn tin Trước tiên ta xét toán sử dụngtrong kỳ thi Olympic Tin học sinh viên Thủ đô năm 1998 Bài Giá trị biểu thức Giả thiết X,Ylà hai số nguyên dương Kí hiệu Sx tổng chữ số dạngbiểu diễn số 10 X, Dmax_y chữ số lớn Dmin_y chữ số nhỏnhất dạng biểu diễn số 10 Y Phép tính hai ngơi # với toánhạng nguyên dương X,Y định nghĩa sau: ( X#Y ) = Sx*Dmax_y+ Dmin_y Ví dụ: (30#9) = 3*9 +9 = 36 (9#30) = 9*3 +0 = 27 Với X chotrước, 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 K Cho X K (0 < X,K < 109-1) cần xác định sốít m phép # để từ xây dựng biểu thức thuộc dạng xét vớiX cho kết K biểu diễn biểu thức Dữ liệu vào từfile văn BT.IN, dòng thứ chứa X, dòng thứ hai chứa K Kết filevăn BT.OUT, dòng thứ chứa m, dịng thứ hai chứa biểu thức Ví dụ: BT.IN 718 BT.OUT 81 ((718 #(718 #718)) #718) *** Thực đề bàinày dễ hiểu không phức tạp lắm, ta vào phân tích tìm lời giảicho toán Trước tiên nhận xét cho < X, K < 109 nên: ≤ Sx ≤ 9*9 ≤ Dmax_x ≤ ≤ Dmin_x ≤ Từ ≤ X#X ≤ 9*9*9+9 = 738, tức biểu thức có dấu # ln mang giá trị đoạn [1,738] Suy rộnghơn giá trị biểu thức hợp lệ phải nằm đoạn [1,738],đây cốt lõi lời giải cho tốn Rõ ràng ta chỉchấp nhận giá trị K thoả mãn ≤ K ≤ 738, K nằm khoảng chắn vơ nghiệm Xét biểu thứcX#X có dấu #, dễ thấy có cách mở rộng biểu thức dấu # là: - X#(X#X) - (X#X)#X - (X#X)#(X#X) Giả sử B mộtbiểu thức tạo X n dấu # có cách mở rộng biểu thức 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] L[i] cho biết số phép # để từ X tạo kết quảlà i, i=1 738 Dễ thấy mảng L mang tính truy hồi, lần ngược làm cụ thểta thực sau: Khởi tạomảng A[1 738] := 0, mảng A đánh dấu giá trị tạo từ biểu thức có Xvà #; khởi tạo mảng L nhận giá trị Maxint Tìm T=X#X;A[T]:=1; L[T]:=1 Thực hiệnbước mảng L khơng cịn bị thay đổi: For i:=1 to 738 Nếu A[i]=1 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 biểu thức cần tìm Để hồn thiện chương trình tất nhiên phải thiết kếthêm mảng lưu trữ để sau in kết đưa vịtrí dấu # dấu ngoặc biểu thức Trong chương trình đây, mảngPre D có chức Sau tồn văn chương trình giả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) 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) 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 L[i]:=maxint; { -} t:=TinhGiaTri(x,x); a[t]:=1; l[t]:=1; stop:=false; while not stop begin stop:=true; for i:=1 to nmax if a[i]=1 then begin t:=TinhGiaTri(x,i); if l[t]>l[i]+1 then begin a[t]:=1; l[t]:=l[i]+1; pre[t]:=i; d[t]:=1; stop:=false; end; { -} t:=TinhGiaTri(i,x); if l[t]>l[i]+1 then begin a[t]:=1; l[t]:=l[i]+1; pre[t]:=i; d[t]:=2; stop:=false; end; { -} t:=TinhGiaTri(i,i); if l[t]>2*l[i]+1 then begin a[t]:=1; l[t]:=2*l[i]+1; pre[t]:=i; d[t]:=3; stop:=false; end; end; end; procedure path(t:integer); begin if pre[t]0 then begin write(f,'('); case d[t] of 1: begin write(f,x,'#'); path(pre[t]); end; 2: begin path(pre[t]); write(f,'#',x); end; 3: begin path(pre[t]); write(f,'#'); path(pre[t]); end; end; write(f,')'); end else write(f,'(',x,'#',x,')'); end; procedure Xuly_Inkq; begin assign(f,out); rewrite(f); if k>738 then writeln(f,'0') else begin TimBieuThuc; if a[k]=0 then writeln(f,'0') else begin writeln(f,l[k]); path(k); end; end; close(f); end; BEGIN clrscr; Nhap; Xuly_Inkq; END Nhận thấy khoá giớihạn kết biểu thức từ chịu khó suy nghĩ từ khố nàycó thể mở ra, phát triển thành nhiều toán tương tự Tiếp theo ta phântích tốn khác có cách giải, dĩ nhiên, qui hoạch động ởmột hình thức biểu khác Bài : Lịch thuê nhân công Có dự án kéo dài T tháng người quản lýcần phải lập lịch sử dụng công nhân dự án, biết số công nhân tốithiểu cần tháng Mỗi thuê hay sa thải cơng nhân phảimất chi phí xác định, công nhân thuê nhận lương thángngay không sử dụng làm việc Với cơngnhân, người quản lý biết chi phí thuê, chi phí sa thải tiền lương phải trảcho cơng nhân tháng Và tốn đặt sau: Cần phải thuê haysa thải cơng nhân tháng để tổng chi phí dành cho nhân công dựán nhỏ nhất, tức giảm tối đa chi phí dự án Dữ liệu vào từfile văn EMPLOY.IN có cấu trúc sau: - Dòng đầughi T số tháng diễn dự án (T=sbd[k-1,s]+x[t]) then begin sbd[k,t]:=sbd[k-1,s]+x[t]; trai[k,t]:=xmo[t,4]; prex[k,t]:=s; end; end; end; temp:=maxint; for k:=1 to if temp>sbd[n,k] then begin temp:=sbd[n,k]; ttc:=k; end; end; procedure Xuly; var i,j,k,ttc:byte; temp:integer; begin for i:=1 to m begin for j:=0 to ttmax begin d[i,j]:=maxint; for k:=0 to ttmax begin Tinh_xoay(i,k,j,temp,ttc); if d[i,j]>d[i-1,k]+temp then begin d[i,j]:=d[i-1,k]+temp; pre[i,j]:=k; end; end; end; end; end; procedure Sua_Mang_Ăi,ttc:byte); var k,t:byte; begin for k:=n downto begin case ttc of 2:xoay90(a[i,k],a[i,k]); 3:xoay180(a[i,k],a[i,k]); 4:xoay270(a[i,k],a[i,k]); end; ttc:=prex[k,ttc]; end; end; procedure Inkq; var min,temp:integer; i,j,k,ttc,vt:byte; begin min:=maxint; for i:=0 to ttmax if d[m,i] begin min:=d[m,i]; vt:=i; end; { -} assign(f,out); rewrite(f); if minmaxint then begin writeln(f,min); for i:=m downto begin Tinh_Xoay(i,pre[i,vt],vt,temp,ttc); Sua_mang_Ăi,ttc); vt:=pre[i,vt]; end; for i:=1 to m begin for j:=1 to n for k:=1 to write(f,a[i,j,k]:2); writeln(f); end; end else writeln(f,'No Solution.'); close(f); end; BEGIN clrscr; Nhap; KhoiTao; XuLy; Inkq; END Phải nói "Xoay ơ" qui hoạch độnghay, đặc biệt lại chứa đựng bên toán khác dùng quihoạch động để giải Tuy nhiên N=8 chương trình chạy lâu, cóhạn chế cách giải thực thi N ≥ ... hoạch động? ?ể giải bạn thấy qui hoạch động phương pháp chung,khi áp dụng vào khác, không giống Để minh họa điềunày, mời bạn đón đọc tiếp số sau ta xét thêm số toán tinkhá hấp dẫn Một số toán quy. .. đ? ?giải cho dù duyệt tốt đến chạy với test cókích thước tối đa Thế lại dùng qui hoạch động giải quy? ??tvới độ phức tạp tính tốn khơng cao cỡ O(2N*M) Và ta phân tíchcụ thể cách giải qui hoạch động. .. lại qui hoạch động Tuy nhiên cũngkhơng q phức tạp lắm, bạn thử tự giải xem Quay trở lạibài xoay ô chúng ta, vấn đề trạng thái dòng giải quy? ??t, giờlà kết hợp trạng thái dòng để đưa lời giải chung