PHƯƠNG PHÁP QUY HOẠCH ĐỘNG

21 556 1
PHƯƠNG PHÁP QUY HOẠCH ĐỘNG

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

PHƯƠNG PHÁP QUY HOẠCH ĐỘNG (Đặng Tuấn Thành – THPT Chuyên Nguyễn Tất Thành, tỉnh Yên Bái) Tư tưởng phương pháp quy hoạch động sử dụng bảng để lưu trữ lời giải toán giải Khi giải toán cần đến nghiệm toán cỡ nhỏ hơn, ta cần lấy lời giải bảng mà không cần phải giải lại Chính mà thuật toán thiết kế phương pháp quy hoạch động hiệu Để giải toán phương pháp quy hoạch động, cần tiến hành cơng việc sau: 1) Tìm tham số mơ tả tốn; 2) Tìm nghiệm tốn nhỏ nhất; 3) Tìm cơng thức (hoặc quy tắc) xây dựng nghiệm tốn thơng qua nghiệm toán cỡ nhỏ hơn; 4) Tạo bảng (dựa tham số mơ tả tốn) để lưu trữ nghiệm tốn Tính nghiệm tốn theo cơng thức tìm lưu trữ vào bảng; 5) Từ tốn giải để tìm nghiệm tốn Lớp toán giải phương pháp quy hoạch động • Bài tốn tối ưu o Max / Min • Bài tốn đếm o Đếm số cấu hình o Thứ tự từ điển • Bài tốn lập bảng phương án o Xây dựng cấu hình o Trị chơi Các cách cài đặt • Bottom-up (từ lên) o Khi xác định thứ tự tốn cần giải o Cài đặt vịng lặp o Có thể giải thừa tốn khơng cần thiết • Top-down (từ xuống) o Khơng cần thiết xác định thứ tự toán cần giải o Cài đặt đệ quy có nhớ  đặt cận o Chỉ giải toán cần thiết Độ phức tạp thuật toán thiết kế theo phương pháp quy hoạch động Giả sử tốn mơ tả tham số cần tính hàm mục tiêu Khi đó, số tốn (hay cịn gọi số trạng thái) cần tính Gọi độ phức tạp tính nghiệm tốn thơng qua nghiệm tốn cỡ nhỏ (cịn gọi chi phí chuyển trạng thái) Khi độ phức tạp thuật tốn bằng: Số trạng thái ( chi phí chuyển trạng thái ) Những vấn đề cần ý giải toán phương pháp quy hoạch động Tìm tham số mơ tả tốn Việc tìm tham số mơ tả tốn dựa đặc điểm, tính chất tốn (cơng việc cịn gọi đốn nhận trạng thái) Cụ thể, cần xác định có tham số nào, ý nghĩa tham số, miền giá trị tham số Đây công việc quan trọng mang ý nghĩa định đến việc giải toán Tối ưu thuật tốn Qua cách tính độ phức tạp thuật toán theo phương pháp quy hoạch động (độ phức tạp số trạng thái nhân với chi phí chuyển trạng thái) ta nhận thấy, để giảm độ phức tạp thuật tốn giảm thiểu số trạng thái giảm chi phí chuyển trạng thái Một số ví dụ minh hoạ Bài toán 1: Bài toán túi Trong siêu thị có n gói hàng (n ≤ 100), gói hàng thứ i có trọng lượng W[i] ≤ 100 trị giá V[i] ≤ 100 Một tên trộm đột nhập vào siêu thị, tên trộm mang theo túi mang tối đa trọng lượng M (M ≤ 100) Hỏi tên trộm lấy gói hàng để tổng giá trị lớn Input: file văn BAG.INP - Dòng 1: Chứa hai số n, M cách dấu cách n dòng tiếp theo, dòng thứ i chứa hai số nguyên dương W[i], V[i] cách dấu cách Output: file văn BAG.OUT - Dòng 1: Ghi giá trị lớn tên trộm lấy Dịng 2: Ghi số gói bị lấy BAG.INP BAG.OUT 11 11 33 521 44 54 10 44 Bài giải: Nếu gọi F[i, j] giá trị lớn có cách chọn gói {1, 2, …, i} với giới hạn trọng lượng j Thì giá trị lớn chọn số n gói với giới hạn trọng lượng M F[n, M] Cơng thức truy hồi tính F[i, j] Với giới hạn trọng lượng j, việc chọn tối ưu số gói {1, 2, …, i - 1, i} để có giá trị lớn có hai khả năng: o Nếu khơng chọn gói thứ i F[i, j] giá trị lớn cách chọn số gói {1, 2, …, i - 1} với giới hạn trọng lượng j Tức F[i, j] = F[i - 1, j] o Nếu có chọn gói thứ i (tất nhiên xét tới trường hợp mà W[i] ≤ j) F[i, j] giá trị gói thứ i V[i] cộng với giá trị lớn có cách chọn số gói {1, 2, …, i - 1} với giới hạn trọng lượng j - W[i] Tức mặt giá trị thu được: F[i, j] = V[i] + F[i - 1, j - W[i]] Vì theo cách xây dựng F[i, j] giá trị lớn có thể, nên F[i, j] max giá trị thu Cơ sở quy hoạch động: Dễ thấy F[0, j] = giá trị lớn cách chọn số gói = Tính bảng phương án: Bảng phương án F gồm n + dòng, M + cột, trước tiên điền sở quy hoạch động: Dòng gồm tồn số Sử dụng cơng thức truy hồi, dùng dịng tính dịng 1, dùng dịng tính dịng 2, v.v… đến tính hết dịng n Truy vết Tính xong bảng phương án ta quan tâm đến F[n, M] giá trị lớn thu chọn n gói với giới hạn trọng lượng M Nếu F[n, M] = F[n 1, M] tức khơng chọn gói thứ n, ta truy tiếp F[n - 1, M] Còn F[n, M] ≠ F[n 1, M] ta thơng báo phép chọn tối ưu có chọn gói thứ n truy tiếp F[n - 1, M W[n]] Cứ tiếp tục truy lên tới hàng bảng phương án program Bag; const InputFile = 'BAG.INP'; OutputFile = 'BAG.OUT'; max = 100; var W, V: Array[1 max] of Integer; F: array[0 max, max] of Integer; n, M: Integer; procedure Enter; var i: Integer; fi: Text; begin Assign(fi, InputFile); Reset(fi); ReadLn(fi, n, M); for i := to n ReadLn(fi, W[i], V[i]); Close(fi); end; procedure Optimize; var i, j: Integer; begin FillChar(F[0], SizeOf(F[0]), 0); for i := to n for j := to M begin {Tính F[i, j]} F[i, j] := F[i - 1, j]; if(j>=W[i])and(F[i,j] j, tức số đầu trái lớn số đầu phải, ta quy ước đặt p(i, j) = - Nếu i = j p(i, i) = dãy khảo sát chứa kí tự nên đối xứng - Nếu i < j s[i] = s[j] p(i, j) = p(i + 1, j – 1) + Vì hai kí tự đầu cuối dãy s[i,j] giống nên cần xác định chiều dài dãy đối xứng dài đoạn s[i + 1, j – 1] cộng thêm đơn vị ứng với hai kí tự đầu cuối dãy - Nếu i < j s[i] ≠ s[j], tức hai kí tự đầu cuối dãy s[i j] khác ta khảo sát hai dãy s[i (j – 1)] s[(i + 1) j] để lấy chiều dài dãy đối xứng dài hai dãy làm kết quả: p(i,j) = max(p(i,j-1),p(i+1,j)) Vấn đề đặt cần tính p(1, n) Mà muốn tính p(1, n) ta phải tính p(i, j) với i, j = n Phương án đệ quy Phương án đệ quy mơ tả hàm ngun rec(i, j) tính trực tiếp giá trị p(i, j) theo tính chất liệt kê Đáp số cho tốn n-rec(1,n) function rec(i,j: integer): integer; begin if i > j then rec := else if i = j then rec := else {i < j} if s[i] = s[j] then rec := rec(i+1,j-1)+2 else {i < j & s[i] ≠ s[j]} rec := max(rec(i,j-1),rec(i+1,j)); end; Dùng mảng hai chiều Gọi đệ quy phát sinh lời gọi hàm trùng lặp Khắc phục điều cách sử dụng mảng hai chiều để tính trước giá trị hàm p(i, j), giá trị tính tối đa lần Nếu dùng mảng hai chiều, thí dụ mảng p[0 n, n] giá trị p[i, j] điền theo cột, từ cột thứ đến cột thứ n Tại cột ta điền từ lên Ta lưu ý: - Phần tử cột i, dịng j giá trị p[i, j] chiều dài dãy đối xứng dài khảo sát dãy s[i j] - Với trị i > j, ta quy định p[i, j] = Như nửa tam giác ma trận p chứa tồn - Nếu i = j p[i, j] = Như vậy, trị đường chéo ma trận p - Với cịn lại, toạ độ (i, j) thoả điều kiện i < j, nên p[i, j] tính sau: if s[i] = s[j] then p[i,j] = p[i+1,j-1]+2 else p[i,j] := max(p[i,j-1],p[i+1,j]); Ta thực điền vài giá trị cho bảng để rút quy luật Hãy bắt đầu với cột 1: p[1, 1] = 0; Sau đến cột 2: p[2, 2] = 1; p[1, 2] = max(p[1, 1], p[2, 2]) = 1, s[1] ≠ s[2] Rồi đến cột 3: p[3,3]=1; p[2,3] = max(p[2, 2], p[3, 3]) = 1, s[2] ≠ s[3]; p[1,3] = max(p[1,2], p[2,3]) = 1, s[1] ≠ s[3],… Dùng hai mảng chiều Ta không theo đuổi phương án dùng mảng hai chiều mà vào quy luật điền mảng hai chiều để vận dụng cho hai mảng chiều v[0 (n + 1)] d[0 (n + 1)] Theo kinh nghiệm, ta nên khai báo kích thước mảng rộng chừng hai phần tử để sử dụng phần tử lính canh chứa giá trị khởi đầu phục vụ cho trường hợp số i, j nhận giá trị n + Giả sử mảng v chứa giá trị điền cột j – mảng hai chiều p Ta điền giá trị cho cột j mảng p vào mảng chiều d Như vậy, bước j, phần tử v[i] ứng với phần tử p[j – 1, i] phần tử d[i] ứng với p[j, i] Thủ tục điền trị cho cột d bước j dựa theo kết lưu cột v bước j – sau: for i := j-1 downto begin if s[i] = s[j] then d[i] := v[i+1]+2 else d[i] := max(v[i],d[i+1]); end; Sau lần lặp với j := n ta chuyển giá trị d cho v để chuẩn bị cho bước procedure QHD; var i,j: integer; begin fillchar(v,sizeof(v),0); for j := to n begin d[j] := 1; for i := j-1 downto begin if s[i]= s[j] then d[i] := v[i+1]+2 else d[i] := max(v[i],d[i+1]); end; v := d; end; writeln(nl,n-d[1]); {dap so} end; Bài toán 3: Chia thưởng Cần chia hết m phần thưởng cho n học sinh theo thứ tự từ giỏi trở xuống cho bạn không nhận phần thưởng bạn xếp sau ≤ m, n ≤ 70 Hãy tính số cách chia Thí dụ, với số phần thưởng m = 7, số học sinh n = có 11 cách chia phần thưởng cho học sinh theo yêu cầu đầu Đó là: Phương án     0 0 0 1 0 3 2 1 10 1 11 2 Bài giải Bước 1: Lập hệ thức Gọi Chia(i, j) số cách chia i phần thưởng cho j học sinh, ta thấy: • Nếu khơng có học sinh (j = 0) khơng có cách chia (Chia = 0) • Nếu khơng có phần thưởng (i = 0) có cách chia (Chia(0,j) = học sinh nhận phần thưởng) Ta quy ước Chia(0, 0) = • Nếu số phần thưởng số học sinh (i < j) phương án chia, từ học sinh thứ i + trở không nhận phần thưởng nào: Chia(i, j) = Chia(i, i) i < j Ta xét tất phương án chia trường hợp i ≥ j Ta tách phương án chia thành hai nhóm không giao dựa số phần thưởng mà học sinh đứng cuối bảng thành tích, học sinh thứ j, nhận: - Nhóm thứ gồm phương án học sinh thứ j khơng nhận thưởng, tức i phần thưởng chia cho j - học sinh đó, số cách chia, tức số phần tử nhóm là: Chia(i, j - 1) - Nhóm thứ hai gồm phương án học sinh thứ j nhận thưởng Khi đó, học sinh đứng cuối bảng thành tích nhận thưởng học sinh khác có thưởng Do thưởng nên ta bớt người phần thưởng (để họ lĩnh sau), số phần thưởng lại (i - j) chia cho j học sinh Số cách chia Chia(i - j, j) Tổng số cách chia cho trường hợp i ≥ j tổng số phần tử hai nhóm, ta có: Chia(i, j) = Chia(i, j - 1) + Chia(i - j, j) Tổng hợp lại ta có: Điều kiện i: số phần thưởng Chia(i, j) j: số học sinh j=0 Chia(i, j) = i = and j ≠ Chia(i, j) = i } if i = then {i = 0; j > } Chia := else {i,j > } if i < j then {0 < i < j } Chia := Chia(i,i) else {i >= j > } Chia := Chia(i,j-1)+Chia(i-j,j); end; Phương án chạy chậm phát sinh nhiều lần gọi hàm trùng lặp Bảng liệt kê số lần gọi hàm Chia giải toán chia thưởng với bảy phần thưởng (m = 7) học sinh (n = 4) Thí dụ, hàm Chia(1,1) gọi lần,… Tổng số lần gọi hàm Chia 79 79 lần gọi hàm để sinh kết 11 tốn Bước 3: Làm tốt Phương án dễ triển khai chương trình chạy lâu Diễn tả đệ quy thường sáng, nhàn tản, thực sinh tượng gọi lặp lại hàm đệ quy Cải tiến tránh lần gọi lặp Muốn tính sẵn giá trị hàm theo trị đầu vào khác điền vào mảng hai chiều cc 11       1  9  6 0  5 1  3 1  2 0  1 0  1 1 Số lần gọi hàm Chia cục tính hàm Chia(7,4) Mảng cc mô tả sau: j-1 j i-j [i-j,j] i [i,j1] [i,j] Const MN = 70;{ gioi han tren cua m va n } var cc: array[0 MN,0 MN] of longint; Ta quy ước cc[i, j] chứa số cách chia i phần thưởng cho j học sinh Theo phân tích phương án 1, ta có:  cc[0, 0] = 1; cc[i, 0] = 0, với i:=1 m  cc[i, j] = cc[i, i], i < j  cc[i, j] = cc[i, j-1]+cc[i-j, j], i ≥ j Từ ta suy quy trình điền trị vào bảng cc sau:  Khởi trị  cc[0,0 ]:= 1;  với i := m: cc[i,0] := 0;  Điền bảng: Lần lượt điền theo cột j:= n Tại cột j ta đặt:  với i := j-1: cc[i,j] := cc[i,i];  với i := j m: cc[i,j] := cc[i,j-1]+cc[i-j,j]; Nhận kết quả: Sau điền bảng, giá trị cc[m, n] kết cần tìm Phương án dùng mảng chiều: function Chia2(m,n: integer):longint; var i,j: integer; begin cc[0,0] := 1; for i := to m cc[i,0] := 0; for j := to n begin 12 for i := to j-1 cc[i,j] := cc[i,i]; for i := j to m cc[i,j] := cc[i,j-1]+cc[i-j,j]; end; Chia2 := cc[m,n]; end; Bài toán Bảng số (VOIR2_2012) Giả sử A lưới ô vuông gồm m dòng n cột Các dòng lưới đánh số từ đến m, từ xuống Các cột lưới đánh số từ đến n, từ trái sang phải Ô nằm giao dòng i cột j lưới gọi ô (i, j) Với số nguyên dương x, gọi f(x) số lượng số nguyên dương không vượt x mà biểu diễn nhị phân có hai bít đứng cạnh Ví dụ, f(5)=1 số nguyên dương bé có số có biểu diễn nhị phân với hai bít đứng cạnh Cho dãy số nguyên dương gồm m×n số b1, b2, , bm×n Ta điền số hạng dãy f(b1) mod 3, f(b2) mod 3, , f(bm×n) mod vào lưới A theo thứ tự từ xuống từ trái qua phải Gọi bảng số thu B Xét truy vấn sau bảng số thu B: Cho hai số nguyên p q (1 ≤ p ≤ q ≤ m), cho biết diện tích lớn hình chữ nhật gồm nằm phạm vi từ dòng thứ p đến dòng thứ q bảng B mà chênh lệch phần tử lớn phần tử nhỏ không vượt Yêu cầu: Cho m, n, dãy số b 1, b2, , bm×n k pi, qi (i = 1, 2, , k) tương ứng với k truy vấn, đưa câu trả lời cho k truy vấn Dữ liệu: Vào từ file văn NUMTAB.INP đó: • Dịng chứa hai số nguyên m, n (1 ≤ m, n ≤ 1000); • Dịng chứa dãy số b1, b2, , bm×n (mỗi số khơng vượt q 109); • Dịng chứa số nguyên k (1 ≤ k ≤ 106); • Dòng thứ i số k dòng chứa số nguyên pi qi (i = 1, 2, , k) Hai số liên tiếp dòng ghi cách dấu cách Kết quả: Ghi file văn NUMTAB.OUT gồm k dòng, dòng chứa số câu trả lời cho truy vấn theo thứ tự xuất liệu vào Ví dụ: NUMTAB.INP NUMTAB.OUT 13 33 387632466 11 12 13 33 4 Tìm hiểu chương trình giải sau (sẽ trao đổi tập huấn) #include #include using namespace std; const int MAX = 1000+5; int a[MAX][MAX], m, n; int kq01[MAX][MAX], kq12[MAX][MAX], w[MAX][MAX]; int xLen, xArr[32]; int fx[20][2][2][2][2]; int fy[1

Ngày đăng: 14/10/2015, 14:42

Từ khóa liên quan

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

Tài liệu liên quan