Thuật toán Quan hệ động và tổ chức dữ liệu

9 834 8
Thuật toán Quan hệ động và tổ chức dữ liệu

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

Thông tin tài liệu

Thuật toán Quan hệ động và tổ chức dữ liệu

Tổ chức dữ liệu cho các bài toán quy hoạch độngNguyễn Xuân HuySố trước ta đã bàn về việc tiết kiệm biến tăng tốc cho các thủ tục quy hoạch động. Số này sẽ minh họa thêm một số bài toán từ các kỳ thi học sinh giỏi địa phương quốc tế.Sơ đồ giải bài toán QHĐ:1. Lập hệ thức:Lập hệ thức biểu diễn tương quan quyết định của bước đang xử lý với các bước đã xử lý trước đó. Hệ thức này thường là các biểu thức đệ quy do đó dễ gây ra hiện tượng tràn miền nhớ khi ta tổ chức chương trình trực tiếp bằng đệ quy.2. Tổ chức dữ liệu chương trình: Tổ chức dữ liệu tính toán dần theo từng bước, nên tìm cách khử đệ quy. Thông thường, trong các bài toán chúng ta hay gặp đòi hỏi một vài mảng hai chiều.3. Làm tốt: Làm tốt thuật toán bằng cách thu gọn hệ thức QHĐ giảm kích thước miền nhớ.Dưới đây là thí dụ minh hoạ.Bài toán 1. (Cắm hoa, đề thi Olimpic Quốc tế năm 1999) Cần cắm k bó hoa khác loại nhau vào n lọ xếp thẳng hàng sao cho hoa có số hiệu nhỏ được đặt trước hoa có số hiệu lớn. Với mỗi loại hoa i ta biết giá trị thẩm mỹ khi cắm hoa đó vào lọ j, v[i,j]. Các số liệu đều là số tự nhiên được ghi cách nhau bởi dấu cách trên mỗi dòng.Dữ liệu vào ghi trong tệp văn bản HOA.INP: dòng đầu tiên là hai trị k n. Từ dòng thứ hai trở đi là các giá trị v[i,j] với i:=1 k j:=1 n; 1 ≤ k ≤ n ≤ 100.Dữ liệu ra ghi trong tệp văn bản HOA.OUT gồm hai dòng: dòng đầu tiên là tổng giá trị thẩm mỹ của phương án cắm hoa tối ưu. Từ dòng thứ hai là dãy k số hiệu lọ được chọn cho mỗi bó hoa.Thí dụ: Bài giải:Trước hết ta đọc dữ liệu từ tệp HOA.INP vào các biến k, n v[i,j].Procedure doc;var i,j:byte;Beginassign(f,fn); reset(f);readln(f,k,n);for i:=1 to k dofor j:=1 to n doread(f,v[i,j]);close(f);End;Các hằng biến được khai báo như sau:const fn = 'hoa.inp';gn = 'hoa.out';mn = 100;bl = ' ';kk = 15;type pt = 0 mn; t1 = array[0 kk] of byte;varn,k : byte;v:array[pt,pt] of integer;L:array[pt] of t1;T:array[pt] of integer;f,g: text;1. Lập hệ thức: Gọi T(i,j) là giá trị thẩm mỹ khi cắm i bó hoa vào j lọ, ta thấy: 1.1. Nếu số bó hoa nhiều hơn số lọ, i > j thì không có cách cắm nào. 1.2. Nếu số bó hoa bằng số lọ, i = j thì chỉ có một cách cắm là bó nào vào lọ đó.1.3. Ta xét trường hợp số bó hoa ít hơn hẳn số lọ i < j. Có hai tình huống: lọ cuối cùng, tức lọ thứ j được chọn cho phương án tối ưu lọ thứ j không được chọn: Nếu lọ thứ j được chọn tức là trong lọ đó ta sẽ cắm bó hoa cuối cùng, bó thứ i. Số i-1 bó hoa đầu tiên sẽ được phân phối vào j-1 lọ đầu tiên. Giá trị thẩm mỹ khi đó sẽ là: T(i-1,j-1)+v[i,j]. Nếu lọ thứ j không được chọn cho phương án tối ưu thì i bó hoa phải được cắm vào j-1 lọ đầu tiên do đó giá trị thẩm mỹ sẽ là: T(i,j-1). Tổng hợp lại ta có giá trị tối ưu khi cắm i bó hoa vào j lọ sẽ là: T(i,j)=max {T(i-1,j-1)+v[i,j], T(i,j-1)}.2. Tổ chức dữ liệu chương trình: Nếu dùng mảng 2 chiều T thì ta có thể tính như trong bảng dưới đây: Ngoài ra ta còn cần đặt trong mỗi ô của bảng trên một mảng dữ liệu bao gồm n phần tử để đánh dấu lọ hoa nào được chọn cho mỗi tình huống. Gọi mảng dữ liệu đó là L[i,j], ta dễ thấy là nên điền bảng lần lượt theo từng cột, tại mỗi cột ta điền bảng từ trên xuống hoặc dưới lên theo luật sau:Nếu T[i-1,j-1]+v[i,j] > T[i,j-1] thì ta phải thực hiện 2 thao tác:+Đặt lại trị T[i,j]:= T[i-1,j-1]+v[i,j], và+Ghi nhận việc chọn lọ hoa j trong phương án mới, cụ thể lấy phương án cắm hoa (i-1,j-1) rồi bổ sung thêm việc chọn lọ hoa j như sau:- Đặt L[i,j]:=L[i-1,j-1] đánh dấu phần tử j trong mảng L[i,j].-Nếu T[i-1,j-1]+v[i,j] ≤ T[i,j-1] thì ta chỉ cần copy L[i,j-1] sang L[i,j], vì ta bảo lưu phương án (i,j-1). 3. Làm tốt: Phương án dùng mảng hai chiều tốn kém về miền nhớ. Ta có thể dùng một mảng một chiều T[0 100] xem như một cột của bảng T nói trên. Ta duyệt j bước, tại bước thứ j, giá trị T[i] sẽ là trị tối ưu khi cắm i bó hoa vào j lọ. Như vậy, tại bước thứ j ta có:- Nếu T[i-1] cũ + v[i,j] > T[i] cũ thì ta phải thực hiện 2 thao tác:+Đặt lại trị T[i]:= T[i-1] cũ + v[i,j], và+Ghi nhận việc chọn lọ hoa j trong phương án mới, cụ thể lấy phương án cắm hoa (i-1) ở bước j-1 rồi bổ sung thêm việc chọn lọ hoa j như sau:- Đặt L[i]:=L[i-1] cũ đánh dấu phần tử j trong mảng L[i].-Nếu T[i-1] cũ + v[i,j] ≤ T[i] cũ thì ta không phải làm gì vì sẽ bảo lưu phương án cũ. Biểu thức so sánh cho biết khi cập nhật mảng T từ bước thứ j-1 qua bước thứ j ta phải tính từ dưới lên, nghĩa là tính dần theo chiều giảm của i := j 1. Để đánh dấu các lọ hoa ta dùng mảng L[0 MN] mỗi phần tử là một dãy 15 byte. Nếu dùng một bit cho mỗi lọ hoa thì với 15 byte ta có thể đánh dấu cho 15*8=120 lọ hoa. Khi cần đánh dấu lọ hoa thứ j trong dãy L[i] ta bật bít thứ j. Khi cần xem lọ thứ j có được chọn hay không ta gọi hàm GetBit.Ta chú ý tới hai biểu thức sau: -Để xác định byte thứ mấy trong dãy chứa bit j ta tính:b := j shr 3 = j div 8; -Để xác định vị trí của bit j trong byte thứ b ta tính:p := j and 7 = j mod 8;Với j=0, tức là khi không có lọ nào không có bó hoa nào ta khởi trị:fillchar(L[0],16,0);T[0]:=0;Với mỗi j=1 n, ta lưu ý số bó hoa phải không lớn hơn số lọ, tức là i ≤ j. Với i=j ta sẽ cắm mỗi bó vào một lọ. Để thực hiện điều này ta lưu ý rằng phần tử L[j-1] tại bước trước đã cho biết j-1 lọ đều có hoa do đó ta chỉ cần đánh dấu lọ thứ j cho bước j là xong:L[j]:=L[j-1];batbit(j,j);Chương trình:uses crt ;const fn = 'hoa.inp';gn = 'hoa.out';mn = 100;bl = ' ';kk = 15;type pt = 0 mn;t1 = array[0 kk]of byte;varn,k : byte;v:array[pt,pt] of integer;L:array[pt] of t1;T:array[pt] of integer; f,g: text;procedure doc;var i,j:byte;beginassign(f,fn); reset(f);readln (f,k,n);for i:=1 to k dofor j:=1 to n doread(f,v[i,j]);close(f);end;function getbit(i,j: byte):byte;var b,p: byte;beginb := j shr 3;p := j and 7;getbit:=(L[i][b] shr p) and 1;end;procedure batbit(i,j:byte);var b,p: byte;beginb := j shr 3;p := j and 7; L[i][b] := L[i][b] or (1 shl p);end;procedure xuly;var i,j:byte;beginfillchar(L[0],16,0);T[0]:=0;for j:=1 to n dobeginL[j]:=L[j-1];batbit(j,j);T[j]:=T[j-1]+v[j,j];for i :=j-1 downto 1 doif T[i] < T[i-1]+v[i,j] thenbeginT[i]:=T[i-1]+v[i,j];L[i]:=L[i-1];batbit(i,j);end;end;end;procedure ghi;var i: byte; beginassign(g,gn) ; rewrite(g);writeln(g,T[k]);for i:=1 to n dobeginif getbit(k,i)=1 then write(g,i,bl);end;close(g);end;procedure BaiLam;begindoc;xuly;ghi;end;BEGINBaiLam;END. Du lieu Test:4 61 1 6 4 3 109 1 4 7 2 77 2 6 10 2 3 6 10 7 1 3 9Ket qua du kien:242 3 4 6Bài toán sau đây là một cách phát biểu khác của bài toán cắm hoa: Bài toán 2. (Câu lạc bộ, Đề thi chọn học sinh giỏi tin Hà Nội, năm 2000) Cần bố trí k nhóm học sinh vào k trong số n phòng học chuyên đề sao cho nhóm có số hiệu nhỏ được xếp vào phòng có số hiệu nhỏ hơn phòng chứa nhóm có số hiệu lớn. Với mỗi phòng có nhận học sinh, các ghế thừa phải được chuyển ra hết, nếu thiếu ghế thì phải lấy từ kho vào cho đủ mỗi học sinh một ghế. Biết số học sinh trong mỗi nhóm số ghế trong mỗi phòng. Hãy chọn phương án bố trí sao cho tổng số lần chuyển ghế ra chuyển ghế vào là ít nhất. . Tổ chức dữ liệu cho các bài toán quy hoạch độngNguyễn Xuân HuySố trước ta đã bàn về việc tiết kiệm biến và tăng tốc cho các thủ tục quy hoạch động. . và chương trình: Tổ chức dữ liệu tính toán dần theo từng bước, nên tìm cách khử đệ quy. Thông thường, trong các bài toán chúng ta hay gặp đòi hỏi một vài

Ngày đăng: 11/09/2012, 15:25

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan