Lập hệ thức.

Một phần của tài liệu Phương pháp quy hoạch động và một số ví dụ cụ thể (Trang 39)

n chíh là phầ tử C[, k] trog mảg

6.3 Lập hệ thức.

Gọi T(i, j) là tổng số lần chuyển ghế ra và chuyển ghế vào khi giải bài toán với i nhóm học sinh mã số 1..ij lớp mã số 1..j, tức là độ thẩm mĩ thu được khi xếp hết i nhóm học sinh đầu tiên vào j lớp đầu tiên, ta thấy:

a) Nếu số nhóm học sinh nhiều hơn số lớp, i > j thì không có cách xếp nào.

T(i, j) = 0

b) Nếu số nhóm học sinh bằng số lớp (i = j) thì chỉ có một cách xếp là nhóm nào vào lớp đó.

c) Ta xét trường hợp số nhóm học sinh ít hơn hẳn số lớp (i < j). Có hai tình huống: lớp cuối cùng, tức lớp thứ j được chọn cho phương án tối ưu và lớp thứ j

không được chọn:

kết quả 24

• Nếu lớp thứ j được chọn để xếp nhóm học sinh i thì i – 1 nhóm học sinh đầu tiên sẽ được phân phối vào j – 1 lớp đầu tiên. Tổng số lần chuyển ghế ra và chuyển ghế vào s khi đó sẽ là

T(i – 1, j – 1) + v[i, j].

• Nếu lớp thứ j không được chọn cho phương án tối ưu thì i nhóm học sinh phải được xếp vào j – 1 lớp đầu tiên và do đó tổng số lần chuyển ghế ra và chuyển ghế vào sẽ là

T(i, j – 1).

Tổng hợp lại ta có giá trị tối ưu khi xếp i nhóm học sinh vào j lớp là:

T(i,j) = max {T(i-1,j-1)+v[i,j],T(i,j-1)}

6.4 Thuật toán.

Nếu dùng mảng hai chiều T thì ta có thể tính như trong bảng dưới đây: Cột j – 1 Cột j

Dòng i – 1 [i-1,j-1]

Dòng i [i,j-1] [i,j]

T(i,j) = max {T(i-1,j-1)+v[i,j],T(i,j-1)}

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ớp 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ừ 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 hai thao tác: • Đặt lại trị T[i, j]:= T[i–1, j–1] + v[i, j].

• Ghi nhận việc chọn lớp j trong phương án mới, cụ thể lấy phương án chọn lớp (i–1, j–1) rồi bổ sung thêm thông tin chọn lớp j như sau: đặt

L[i, j]:= L[i–1, j–1] và đá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 sẽ không chọn lớp j để xếp nhóm học sinh i và do đó chỉ cần sao L[i, j–1] sang L[i, j], tức là ta bảo lưu phương án (i, j–1).

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 xếp hết i nhóm học sinh vào j lớp. Như vậy, tại bước thứ j ta có:

 Nếu T[i–1] tại bước j 1 + v[i, j] > T[i] tại bước j – 1 thì ta phải thực hiện hai thao tác:

• Đặt lại trị T[i] tại bước j:= T[i–1] tại bước j 1 + v[i, j].

• Ghi nhận việc chọn lớp j trong phương án mới, cụ thể lấy phương án chọn lớp (i–1) ở bước j – 1 rồi bổ sung thêm thông tin chọn lớp j như sau: đặt L[i] tại bước j:= L[i – 1] tại bước j 1 và đánh dấu phần tử j

trong mảng L[i].

 Nếu T[i – 1] tại bước j 1 + v[i, j] ≤ T[i] tại bước j 1 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ớp ta dùng mảng L[0..MN] mỗi phần tử L[i] lại là một dãy

s byte. Nếu dùng một bit cho mỗi lớp thì số byte cần dùng để đánh dấu tối đa MN lớp phải là:

kk = (MN+7) div 8

Với MN = 101 ta tính được kk = (101+7) div 8 = 13

Khi cần đánh dấu lớp thứ j trong dãy L[i] ta bật bit thứ j trong L[i]. Khi cần xem lớp thứ j có được chọn hay không ta gọi hàm GetBit để lấy trị (0 hoặc 1) của bit j trong dãy bit L[i].

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 div 8;

 Để xác định vị trí của bit j trong byte thứ b ta tính: p:= j mod 8;

//Cho gia tri bit thu j trong day byte L[i ]

function getbit(i,j: byte):byte;

var b,p: byte; begin b:= j div 8; p:= j mod 8; getbit:=(L[i ][b ] shr p) and 1; end;

//Gan tri 1 cho bit j trong day byte L[i ] procedure batbit(i,j:byte); var b,p: byte; begin b:= j shr 3; p:= j and 7; L[i ][b ]:= L[i ][b ] or (1 shl p); end;

Với j = 0, tức là khi không có lớp nào và không có nhóm học sinh 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ố nhóm học sinh phải không lớn hơn số lớp, tức là

ij. Với i = j ta sẽ xếp mỗi nhóm vào một lớp. Để 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ớp đều có nhóm học sinh do đó ta chỉ cần đánh dấu lớp thứ j cho bước j:

L[j ]:=L[j-1 ]; batbit(j,j);

Như vậy ta cần chia quá trình duyệt theo các lớp từ 1..n thành hai giai đoạn.

Giai đoạn 1: Duyệt từ lớp 1 đến lớp k, trong đó k chính là số nhóm học sinh

và theo đầu bài, kn.

Phương án quy hoạch động với mảng một chiều khi đó sẽ như sau:

procedure xuly;

var i,j: byte;

begin

{1. Khoi tri}

fillchar(L,sizeof(L),0);

{danh dau cac lop duoc chon}

T[0 ]:=0; {do tong so cach}

{Vi co k nhom hoc sinh nen xet k lo dau tien}

for j:=1 to k do begin

L[j ]:=L[j-1]; batbit(j,j);

T[j ]:= T[j-1 ]+v[j,j ];

for i:=j-1 downto 1 do

if T[i ] < T[i-1 ]+v[i,j ] then begin

T[i ]:= T[i-1 ]+v[i,j ]; L[i ]:= L[i-1 ];

batbit(i,j);

end;

end;

{xet cac lop con lai}

for j:=k+1 to n do

for i:= k downto 1 do

begin

T[i ]:= T[i-1 ]+v[i,j ]; L[i ]:= L[i-1 ];

batbit(i,j);

end;

end;

6.5 Tính đúng đắn.

Trong bài toán này ta sử dụng tư tưởng quy hoạch động vào xây dựng công thức truy hồi, và kiểm tra lại bằng đệ quy cùng một kết quả. Nên giải thuật chúng ta sử dụng trên luôn cho kết quả đúng.

6.6 Độ phức tạp thuật toán

Độ phức tạp Đệ quy Quy hoạch động Quy hoạch độngcải tiến

Không gian O(2n) O(2n) O(n)

Thời gian O(2n) O(n2) O(n)

6.7 Ứng dụng

1 Bài toán: Cấp số cộng 1.3 Phát biểu bài toán

Cho một tệp văn bản gồm N (N rất lớn) số nguyên a1, a2, a3,..,an với ai ≤ 30 000. Hãy tìm trong dãy A đó một dãy con dài nhất lập thành một dãy cấp số cộng có công sai là d. Với 0 < d ≤ 100.

Dữ liệu vào:

-Dòng đầu ghi số N

- N dòng tiếp theo ghi các số ứng với dãy A

Dữ liệu ra:

- Dòng đầu ghi số M là số phần tử và công sai của dãy cấp số cộng đó - M dòng tiếp theo ghi số chỉ số của các số thuộc cấp số cộng.

1.4 Ý tưởng 30s

Nếu dữ liệu nhỏ N=10000 thì ta có thể dùng phương pháp duyệt đơn thuần để giải bài toán trên một cách dễ dàng, nhưng với dữ liệu N<=100000 thì quả là

lớn,việc lưu các số này vào mảng là một chuyện không thể, huống chi ta phải duyệt với độ phức tạp N*(N+1 )/2. Nếu duyệt thì ta sẽ không giải quyết được dữ liệu cũng như thời gian.

Các bạn hãy chú ý rằng nếu biết công sai và số đầu hay số cuối thì ta có thể biết được dãy cấp số cộng nó như thế nào, tại sao ta không tìm dãy cấp số cộng dài nhất ứng với một công sai nào đó

1.5 Lập hệ thức

Giả sử cần tìm chiều dài lớn nhất của dãy cấp số cộng có công sai là d.

Suy ra: Fx[i]=Fx[i-d]+1;

Vì đã biết công sai là d nên khi nhập được số k nào đó thì muốn tạo thành cấp số cộng tận cùng bằng k thì số trước đó phải là (k-d). Như vậy chiều dài dài nhất của dãy cấp số cộng tận cùng bằng k sẽ bằng chiều dài dài nhất của dãy cấp số cộng tận cùng là k-d cộng 1.

• Ta có thể khai báo như sau:

Type arr=array[0..30000] of word; var a,b :^arr;

Nhận xét chiều dài tối đa của dãy cấp số cộng là 60001 nên ta khai báo word là vừa đủ.

• Với mảng a dùng cho các số không âm,mảng b dành cho các số âm. A[i] là chiều dài dài nhất của dãy cấp số cộng tận cùng bằng i, B[i] là chiều dài dài nhất của dãy cấp số cộng tận cùng bằng -i,

Vậy để giải quyết bài toán cấp số cộng ta chỉ cần duyệt với từng công sai từ 1 đến 100 là được.

1.6 Thuật toán

Đây là thuật toán sử dụng phương pháp quy hoạch động.

procedure QHD; var i:integer; begin max:=0; for i:=1 to 100 do begin openf; New(a); New(b);

readln(f);

fillchar(a,sizeof(a),0); fillchar(b,sizeof(b),0); while not eof(f) do

begin d:=max; readln(f,k); s:=k-i; if s>=0 then â[k]:=â[s]+1 else begin if k>=0 then a[k]:=b^[abs(s)]+1 else b^[abs(k)]:=b^[abs(s)]+1; end; if max if max if d<>max then begin luu:=i; sc :=k; end; end; dispose(a); dispose(b); closef; end;

end;

1.7 Chứng minh tính đúng đắn

Ta sử dụng công thức tổng quát để tìm ra dãy con có cấp số cộng. Việc sử dụng phương pháp quy hoạch động là chúng ta lưu lại các giá trị đã tính trong mà để không phải gọi lại nhiều lần. Nên rõ ràng công thức này luôn đúng.

1.8 Độ phức tạp thuật toán

• Độ phức tạp không gian O(n)

• Độ phức tạp thời gian O(n)

1.9 Ứng dụng

1 Bài toán: Xóa ít nhất ký tự của một xâu để được xâu đối xứng. 1.10 Phát biểu bài toán

Dãy kí tự s được gọi là đối xứng nếu các phần tử cách đều đầu và cuối giống nhau. Cho dãy s tạo bởi n kí tự gồm các chữ cái hoa và thường phân biệt và các chữ số. Hãy cho biết cần xoá đi từ s ít nhất là bao nhiêu kí tự để thu được một dãy đối xứng. Giả thiết rằng sau khi xoá bớt một số kí tự từ s thì các kí tự còn lại sẽ tự động xích lại sát nhau.

1.11 Ý tưởng 30s

Dữ liệu vào ghi trong tệp văn bản với cấu trúc như sau: Dòng đầu tiên là giá trị n, 1 ≤ n ≤ 1000.

Dòng thứ hai là n kí tự của dãy viết liền nhau.

Ta có thể chọn phương án liệt kê, thử tất cả các cách xóa để thu được dãy con đối xứng.

Thí dụ, với dãy s gồm 9 kí tự, s = 'baeadbadb' thì cần xoá ít nhất 4 kí tự, chẳng hạn, các kí tự thứ 5, 7, 8 và 9 sẽ thu được dãy đối xứng chiều dài 5 là baeab:

baeadbadb → baeab

Dĩ nhiên là có nhiều cách xoá. Thí dụ, có thể xoá các kí tự thứ 2, 3, 4 và 6 từ dãy s để thu được dãy con đối xứng khác là bdadb với cùng chiều dài 5:

baeadbadb → bdadb

Tuy nhiên đáp số là số ít nhất các kí tự cần loại bỏ khỏi s thì là duy nhất và bằng 4.

Bài toán này đã được nhiều bạn đọc công bố lời giải với một mảng hai chiều kích thước n2 hoặc vài ba mảng một chiều kích thước n, trong đó n là chiều dài của dữ liệu vào.

Với một nhận xét nhỏ ta có thể phát hiện ra rằng chỉ cần dùng một mảng một chiều kích thước n và một vài biến đơn là đủ.

Gọi dãy dữ liệu vào là s. Ta tìm chiều dài của dãy con đối xứng v dài nhất trích từ s. Khi đó số kí tự cần xoá từ s sẽ là t = length(s) - length(v). Dãy con ở đây được hiểu là dãy thu được từ s bằng cách xoá đi một số phần tử trong s. Thí dụ với dãy s = baeadbadb thì dãy con đối xứng dài nhất của s sẽ là baeab hoặc bdadb,… Các dãy này đều có chiều dài 5.

Một phần của tài liệu Phương pháp quy hoạch động và một số ví dụ cụ thể (Trang 39)

Tải bản đầy đủ (DOCX)

(78 trang)
w