THUẬT TOÁN QUY HOẠCH ĐỘNG

11 714 1
THUẬT TOÁN 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

THUẬT TOÁN QUY HOẠCH ĐỘNG Nguyễn Hồng Thái Trường THPT Chuyên Hạ Long, Quảng Ninh 1. Giới thiệu thuật toán quy hoạch động Đối với nhiều thuật toán chúng ta đã biết nguyên lý “chia để trị” thường đóng vai trò chủ đạo trong việc thiết kế thuật toán: để giải quyết bài toán lớn, chúng ta chia nó thành nhiều bài toán con có thể được giải quyết độc lập. Trong thuật toán quy hoạch động, việc thể hiện nguyên lý này được đẩy đến cực độ, chúng ta giải quyết các bài toán con và lưu trữ những lời giải này với mục đích sử dụng lại chúng theo một sự phối hợp nào đó để giải quyết các bài toán tổng quát hơn. Cách tiếp cận này được ứng dụng rộng rãi trong vận trù học. Thuật ngữ “quy hoạch động” mà chúng ta đề cập ở đây ngụ ý nói đến quá trình đưa bài toán ban đầu về một dạng nào đó có thể áp dụng phương pháp này để giải. Ý tưởng cơ bản của nó là giải các bài toán con giống như vậy. Dưới đây chúng ta xem xét một vài bài toán cụ thể để qua đó giới thiệu phương pháp tiếp cận này. 2. Thuật toán quy hoạch động trên mảng một chiều Bài toán 1. Cho một dãy gồm n số nguyên: a1, a2, ..., an (1 ≤ n ≤ 105, 0 < ai < 106). Hãy loại bỏ một số ít nhất các phần tử của dãy số và giữ nguyên thứ tự các phần tử còn lại sao cho dãy số còn lại là một dãy tăng. Ta gọi dãy số còn lại sau khi đã loại bỏ một số phần tử là dãy con của dãy đã cho. Như vậy yêu cầu của bài toán cũng đồng nghĩa với việc tìm dãy con tăng dài nhất, tức là nhiều phần tử nhất. Phân tích và thiết kế thuật toán Thuật toán 1: Một thuật toán đơn giản cho bài toán này là thuật toán duyệt và có đánh giá nhánh cận. Rõ ràng với bài toán này thì thuật toán trên sẽ không đáp ứng được yêu cầu về mặt thời gian. Vì vậy ta cần tìm một thuật toán tốt cho bài toán trên. Ý tưởng của thuật toán này là ta sẽ lần lượt đi giải n bài toán con sau: tìm dãy con tăng dài nhất của dãy a1, a2, ..., ai với i = 1, 2, ..., n. Rõ ràng bài toán con cuối cùng (ứng với i = n) là bài toán gốc ban đầu của ta. Mặt khác lời giải của bài toán i sẽ kế thừa lời giải của các bài toán nhỏ trước đó. Vì vậy ta lưu lời giải của các bài toán vào mảng một chiều best[1..n], ở đó best[i] là số phần của dãy con tăng dài nhất của dãy a1, a2, ..., ai với ai là phần tử cuối cùng của dãy con tăng dài nhất nói trên. Ta có công thức truy hồi tính best[i] như sau: best[i] = max{best[j] + 1} với mọi j = 1, 2, ..., (i-1) và aj < ai Nếu các phần tử aj đứng trước ai đều lớn hơn hoặc bằng ai thì công thức trên không xác định được giá trị cho best[i], trong trường hợp này best[i] = 1. Nhìn vào công thức truy hồi trên, ta thấy cần phải khởi tạo giá trị best[1] = 1. Như vậy độ dài của dãy con tăng dài nhất của dãy đã cho sẽ là giá trị lớn nhất của các phần tử mảng best: max{best[i]} với mọi i = 1, 2, …, n. 1 Công việc cuối cùng là tìm các phần tử của dãy con tăng dài nhất. Để làm việc này ta dùng một mảng truoc[1..n] với ý nghĩa truoc[i] là chỉ số của phần tử trước phần tử i trong dãy con tăng dài nhất. Do đó từ mảng truoc ta có thể lấy chỉ số các phần tử thuộc dãy con tăng dài nhất bằng cách lần ngược từ phần tử cuối về phần tử đầu. Vì vậy để in ra các phần tử của dãy con tăng dài nhất ta phải dùng thêm một mảng phụ p và in ngược lại các phần tử của mảng p. Chú ý rằng các phần tử của mảng truoc được khởi tạo bằng 0, do vậy trước của phần tử đầu tiên trong dãy con tăng dài nhất là 0. m := 0; // số phần tử của dãy con tăng dài nhất i := i_max; // i_max là chỉ số của phần tử lớn nhất mảng best while i 0 do begin m := m + 1; p[m] := a[i]; i := truoc[i]; end; Khi đó các phần tử của dãy con tăng dài nhất được in ra bằng dòng lệnh: for i := m downto 1 do writeln(p[i]); Tuy nhiên nếu tinh ý ta có thể nhận ra tính đệ quy trong việc in kết quả. Do đó thủ tục in ra dãy con tăng dài nhất rất ngắn gọn và sáng sủa: procedure print(i : integer); begin if i = 0 then exit; print(truoc[i]); writeln(f, a[i]); end; Công việc in ra chỉ cần một lời gọi: print(i_max); Độ phức tạp thời gian của thuật toán 1 là O(n2). Chương trình được cài đặt như sau. program day_con_tang_dai_nhat_1; const FI = 'dctdn.in'; FO = 'dctdn.out'; var n : longint; a, best, truoc : array[1..100000] of longint; f : text; procedure doc; var i : longint; begin assign(f, FI); reset(f); readln(f, n); for i := 1 to n do readln(f, a[i]); close(f); end; procedure xuli; var i, j : longint; 2 begin for i := 1 to n do begin best[i] := 1; truoc[i] := 0; for j := 1 to (i-1) do if (a[j] < a[i]) and (best[i] < best[j] + 1) then begin best[i] := best[j] + 1; truoc[i] := j; end; end; end; procedure print(i : longint); begin if i = 0 then exit; print(truoc[i]); writeln(f, a[i]); end; procedure ghi; var i, j : longint; begin assign(f, FO); rewrite(f); i := 1; for j := 2 to n do if best[j] > best[i] then i := j; writeln(f, best[i]); print(i); close(f); end; begin doc; xuli; ghi; end. Thuật toán 2: Gọi pj là vị trí của phần tử nhỏ nhất để dãy con tăng có độ dài đúng bằng j trong dãy a1, a2, ..., ai. Ta sẽ sử dụng thuật toán tìm kiếm nhị phân để xây dựng mảng p. Độ phức tạp thời gian của thuật toán 2 là O(n.log2n). program day_con_tang_dai_nhat_2; const FI = 'dctdn.in'; FO = 'dctdn.out'; var n, m : longint; a, p, truoc : array[0..100000] of longint; f : text; procedure doc; var i : longint; begin assign(f, FI); reset(f); readln(f, n); for i := 1 to n do readln(f, a[i]); 3 close(f); end; procedure xuli; var i, j, l, r, c : longint; begin a[0] := -MAXLONGINT; m := 0; p[0] := 0; for i := 1 to n do begin if a[i] < a[p[1]] then j := 0 else if a[i] > a[p[m]] then j := m else begin l := 1; r := m; repeat c := (l+r) div 2; if a[p[c]] < a[i] then l := c else r := c; until l+1 >= r; j := l; end; truoc[i] := p[j]; if (j = m) or (a[i] < a[p[j+1]]) then begin p[j+1] := i; if j = m then inc(m); end; end; end; procedure print(i : integer); begin if i = 0 then exit; print(truoc[i]); writeln(f, a[i]); end; procedure ghi; begin assign(f, FO); rewrite(f); writeln(f, m); print(p[m]); close(f); end; begin doc; xuli; ghi; end. 3. Thuật toán quy hoạch động trên mảng hai chiều Chúng ta có thể gặp các bài toán mà mảng quy hoạch động có kích thước lớn hơn: 2, 3, … chiều, chẳng hạn như bài toán dưới đây. 4 Bài toán 2. Cho 2 dãy số nguyên a1, ..., am và b1, ..., bn. Hãy tìm dãy con chung dài nhất của cả 2 dãy. Phân tích và thiết kế thuật toán Ở đây, bài toán con là tìm dãy con chung dài nhất của 2 dãy nhỏ hơn: dãy gồm i (i = 1, 2, ..., n) phần tử đầu tiên của dãy thứ nhất và dãy gồm j (j = 1, 2, ..., n) phần tử đầu tiên của dãy thứ hai. Ta gọi best[i, j] là độ dài của dãy con chung dài nhất này. Bây giờ ta xét bài toán tìm dãy con chung dài nhất của hai dãy a1, ..., ai và b1, ..., bj với i = 1, ..., m; j = 1, ..., n, giả sử rằng các bài toán với i, j nhỏ hơn đã giải xong. Ta hãy bắt đầu tại hai phần tử cuối cùng của hai dãy, có hai khả năng xảy ra: • Trường hợp thứ nhất a[i] = b[j]: Suy ra best[i, j] = best[i-1, j-1] + 1. • Trường hợp thứ hai a[i] ≠ b[j]: Suy ra best[i, j] = max(best[i, j-1], best[i-1, j]). Nhìn vào công thức truy hồi trên, ta thấy cần phải khởi tạo hàng 1 và cột 1 của mảng best, tức là phải giải bài toán khi 1 trong 2 dãy có một phần tử. Thực ra bài toán cơ sở này là dễ, nhưng để dễ hơn, ta sẽ xét bài toán con của nó là khi có 1 trong 2 dãy là rỗng (i = 0 hoặc j = 0). Lời giải bài toán này đơn giản là không có dãy con chung nào cả. Vì vậy ta sẽ mở rộng mảng best ra thêm hàng 0, cột 0 và thay vì phải khởi tạo cho hàng 1, cột 1 ta sẽ khởi tạo cho hàng 0, cột 0: • best[0, j] = 0 với mọi j = 0, 1, …, n. • best[i, 0] = 0 với mọi i = 0, 1, …, m. Khi đó best[m, n] sẽ là độ dài của dãy con chung dài nhất của hai dãy số đã cho. Hơn nữa, dựa vào mảng best ta có thể đưa ra được một dãy con chung dài nhất. Thuật toán có độ phức tạp thời gian là O(m×n). Cài đặt thuật toán program day_con_chung_dai_nhat; const FI = 'dccdn.in'; FO = 'dccdn.out'; var m, n : integer; a, b : array[1..5000] of longint; best : array[0..5000, 0..5000] of integer; f : text; procedure doc; var i : integer; begin assign(f, FI); reset(f); read(f, m, n); for i := 1 to m do read(f, a[i]); for i := 1 to n do read(f, b[i]); close(f); end; Function max(a, b : integer) : integer; Begin if a > b then max := a else max := b; End; 5 procedure xuly; var i, j : integer; begin for i := 0 to m do best[i, 0] := for j := 0 to n do best[0, j] := for i := 1 to m do for j := 1 to n do if a[i] b[j] then best[i, else best[i, end; 0; 0; j] := max(best[i, j-1], best[i-1, j]) j] := best[i-1, j-1] + 1; procedure print(i, j : integer); begin if best[i, j] = 0 then exit; if a[i] = b[j] then begin print(i-1, j-1); writeln(f, a[i]); end else if best[i, j] = best[i-1, j] then print(i-1, j) else print(i, j-1); end; procedure ghi; begin assign(f, FO); rewrite(f); writeln(f, best[m, n]); print(m, n); close(f); end; begin doc; xuly; ghi; end. 4. Kết luận Như đã nói ở trên, chìa khóa trong thuật toán quy hoạch động là việc xây dựng các bài toán con mà ta gọi là mảng quy hoạch động. Mảng này có thể là 1, 2 hoặc có thể nhiều chiều tùy thuộc vào lời giải của bài toán phụ thuộc vào các loại tham số nào. Tiếp đến là cách quy nạp thu gọn bài toán sau mỗi bước, tức là không gian bài toán (kích thước dữ liệu) nhỏ lại, cho đến khi nào ta hoàn toàn có thể giải được bài toán nhỏ (điểm dừng của quy nạp). Bản chất của công việc này là ta phải xây dựng được lời giải của bài toán qua các bài toán con, tức là lập được công thức truy hồi, và dựa vào công thức truy hồi, ta sẽ biết được cần phải khởi tạo như thế nào. Trong các phần trên, chúng ta đã khảo sát một số bài toán có thể dùng thuật toán quy hoạch động để giải quyết một cách hiệu quả. Những vấn đề này đều liên quan đến bài toán tìm phương án tối ưu để thực hiện một công việc nào đó và chúng có chung một tính chất là đáp án tốt nhất cho một bài toán con vẫn được duy trì khi bài toán con đó trở thành một phần trong bài toán lớn hơn. 6 Thuật toán quy hoạch động thường được áp dụng để giải các bài toán tối ưu, bài toán đếm, … Vì vậy, nếu giới hạn kích thước dữ liệu của các bài toán tối ưu lớn và việc sử dụng các thuật toán khác (như duyệt, nhánh cận, ...) có độ phức tạp thời gian lớn thì chúng ta hãy nghĩ đến thuật toán quy hoạch động. 5. Bài tập áp dụng 1. Triangle Hãy xem tam giác số dưới đây. Hãy viết chương trình tính tổng lớn nhất của các số trên đường đi bắt đầu từ đỉnh và kết thúc đâu đó ở đáy. Mỗi bước có thể đi chéo xuống phía trái hoặc đi chéo xuống phía phải. Trong ví dụ trên, đường đi từ 7 đến 3 đến 8 đến 7 đến 5 sẽ tạo ra tổng lớn nhất là 30. 8 1 0 2 4 4 4 2 6 5 Dữ liệu: Dòng đầu tiên của file vào ghi số nguyên N (1 ≤ N ≤ 1.000) là số lượng hàng của tam giác; Dòng thứ i trong số N dòng tiếp theo, ghi các số trên hàng thứ i của tam giác. Các số ghi cách nhau bởi một dấu cách và có giá trị trong đoạn từ 0 đến 100. Kết quả: Ghi ra file ra tổng lớn nhất của các số trên đường đi theo quy tắc nêu trên. Ví dụ: numtri.in 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 numtri.out 30 2. Piggy-Bank Trước khi nhóm ACM có thể làm một việc gì đó thì cần phải chuẩn bị một ngân sách và sự hỗ trợ tài chính cần thiết. Nguồn thu nhập chính cho việc này là từ tiền tiết kiệm. Ý tưởng này rất đơn giản: bất cứ khi nào mỗi thành viên của nhóm ACM có một số tiền nhỏ, họ lấy tất cả các đồng tiền đó và bỏ chúng vào con lợn đất. Bạn biết rằng, khi bỏ các đồng tiền vào thì không thể lấy các đồng tiền đó ra nếu không đập vỡ con lợn đất. Sau một khoảng thời gian đủ dài thì sẽ có đủ số tiền mặt có trong con lợn đất để chi trả mọi thứ cần thiết. Nhưng có một vấn đề lớn đối với các con lợn đất là không thể xác định có bao nhiêu tiền ở bên trong. Vì vậy, chúng ta chỉ có thể đập vỡ con lợn thành các mảnh nhỏ thì mới biết là có bao nhiêu tiền ở bên trong nó. Rõ ràng chúng ta không muốn tình huống này xảy ra. Tuy nhiên, có một điều mà chúng ta có thể làm được là cân con lợn đất và ước chừng có bao nhiêu tiền ở trong đó. Giả sử rằng chúng ta xác định được chính xác trọng lượng của con lợn và chúng ta biết trọng lượng của tất cả các đồng tiền, thì chúng ta có thể chắn chắn có một lượng tiền tối thiểu ở trong con lợn. Nhiệm vụ của bạn là phải tìm ra trường hợp xấu nhất này và xác định lượng tiền tối thiểu trong con lợn đất đó. Chúng tôi cần sự giúp đỡ của bạn để không có con lợn đất nào bị đập vỡ trước thời hạn. 7 Dữ liệu: Dòng đầu tiên của file vào chứa hai số nguyên E và F. Các số này là trọng lượng của con lợn rỗng và con lợn chứa đầy các đồng tiền. Cả hai trọng lượng là được cho bằng đơn vị gam. Không có con lợn nào nặng quá 10 kg, điều này có nghĩa là 1 ≤ E ≤ F ≤ 10.000. Dòng thứ hai ghi một số nguyên N (1 ≤ N ≤ 500) là số các đồng tiền khác nhau có thể được sử dụng. Tiếp theo có đúng N dòng, mỗi dòng mô tả một loại tiền. Mỗi dòng này chứa hai số nguyên P và W (1 ≤ P ≤ 50.000, 1 ≤ W ≤ 10.000). P là giá trị một đơn vị tiền tệ của loại đồng tiền này, W là trọng lượng của nó tính bằng gam. Kết quả: File ra gồm một dòng ghi đúng một số nguyên là lượng tiền nhỏ nhất có thể có được khi sử dụng các đồng tiền trên để bỏ vào lợn có trọng lượng ban đầu E (lợn rỗng) để đạt đến trọng lượng F. Nếu trọng lượng của lợn không thể đạt được đúng bằng F thì ghi ra câu “impossible” Ví dụ: pig.in 10 110 2 1 1 30 50 1 6 2 10 3 20 4 pig.out 60 impossible 3. Little shop of flowers (IOI ’99) Bạn muốn sắp đặt cửa sổ hiệu bán hoa của mình sao cho hấp dẫn nhất. Bạn có M bó hoa, mỗi bó một loại khác nhau và số bó hoa không nhiều hơn số bình hoa sắp sẵn thành một hàng trên cửa sổ. Các bình hoa được gắn cố định và được đánh số liên tục từ 1 đến N, trong đó N là số bình, theo thứ tự từ trái sang phải sao cho bình 1 là bình bên trái nhất, còn bình N là bình bên phải nhất. Mỗi bó hoa được gán một số nguyên duy nhất có giá trị trong khoảng giữa 1 và M và có thể được cắm vào các bình khác nhau. Số hiệu của các bó hoa có ý nghĩa như sau: bó hoa i nằm bên trái bó hoa j trong dãy các bình hoa nếu i < j. Ví dụ, giả sử ta có một bó hoa Đỗ Quyên (có số hiệu là 1), một bó hoa Thu Hải Đường (có số hiệu là 2) và một bó hoa Cẩm Chướng (có số hiệu là 3). Bây giờ tất cả các bó hoa phải được cắm vào dãy các bình hoa bảo đảm ràng buộc về thứ tự các số hiệu. Bó hoa Đỗ Quyên phải cắm vào bình phía bên trái của bình hoa Thu Hải Đường. Còn bó hoa Thu Hải Đường phải cắm vào bình phía bên trái của bình hoa Cẩm Chướng. Nếu số bình hoa nhiều hơn số bó hoa thì những bình không dùng đến sẽ để trống. Mỗi bình chỉ được cắm 1 bó hoa. Mỗi bình hoa có đặc điểm khác nhau (cũng như bản thân các bó hoa). Vì vậy, khi một bó hoa được cắm vào bình sẽ có một giá trị thẩm mỹ nhất định, được biểu diễn bởi một số nguyên. Các giá trị thẩm mỹ được cho trong bảng dưới đây. Các bình để trống sẽ có giá trị thẩm mỹ bằng 0. Bình hoa Hoa 1 2 3 4 5 1 (Đỗ Quyên) 7 23 -5 -24 16 2 (Thu Hải Đường) 5 21 -4 10 23 3 (Cẩm Chướng) -21 5 -4 -20 20 Theo bảng trên, hoa Đỗ Quyên sẽ rất hấp dẫn khi được cắm vào bình 2, nhưng sẽ khó coi khi cắm vào bình 4. 8 Để nhận được hiệu quả thẩm mỹ tốt nhất, bạn phải tìm cách cắm các bó hoa vào bình tuân theo ràng buộc về thứ tự sao cho tổng các giá trị thẩm mỹ là lớn nhất. Dữ liệu: Dòng đầu tiên của file vào chứa hai số M, N (1 ≤ M ≤ N ≤ 100). M dòng tiếp theo, mỗi dòng chứa N số nguyên sao cho Aij là số thứ j trên dòng thứ (i+1), trong đó Aij là giá trị thẩm mỹ đạt được khi cắm bó hoa i vào bình j (-50 ≤ Aij ≤ 50). Kết quả: File ra chứa hai dòng, dòng 1 ghi giá trị tổng nhận được theo cách cắm của bạn; dòng 2 biểu diễn cách cắm như là một danh sách M số, sao cho số thứ k trong dòng này cho biết bình hoa dùng để cắm bó hoa có số hiệu k. Nếu có nhiều cách cắm cùng cho giá trị tổng lớn nhất thì đưa ra cách cắm nhỏ nhất theo thứ tự từ điển. Ví dụ: flower.in flower.out 3 5 53 7 23 -5 -24 16 2 4 5 5 21 -4 10 23 -21 5 -4 -20 20 4. Palindrome (IOI2000 - Beijing China) Xâu đối xứng là xâu mà việc đọc nó từ trái sang phải cũng như từ phải sang trái. Bạn hãy viết một chương trình, cho trước một xâu và xác định số ký tự nhỏ nhất cần chèn vào xâu để có được một xâu đối xứng. Ví dụ, chèn 2 ký tự vào xâu “Ab3bd” sẽ tạo thành một xâu đối xứng (“dAb3bAd” hoặc “Adb3bdA”). Hơn nữa, việc chèn ít hơn 2 ký tự sẽ không tạo ra một xâu đối xứng. Dữ liệu: File vào gồm 2 dòng. Dòng đầu tiên chứa một số nguyên N là độ dài của xâu vào (3 ≤ N ≤ 5000); Dòng thứ hai chứa một xâu độ dài N. Xâu này chỉ gồm các chữ cái in hoa từ ‘A’ đến ‘Z’, các chữ cái in thường từ ‘a’ đến ‘z’ và các chữ số từ ‘0’ đến ‘9’. Các chữ cái in hoa và in thường được xem là khác nhau. Kết quả: File ra gồm một dòng chứa một số nguyên là số ký tự nhỏ nhất cần chèn như mô tả ở trên. Ví dụ: palin.in 5 Ab3bd palin.out 2 5. Truyền tin Người ta cần truyền n gói tin được đánh số từ 1 đến n từ một điểm phát đến một điểm thu. Để thực hiện việc truyền tin có thể sử dụng m đường truyền được đánh số từ 1 đến m. Biết rằng nếu truyền j gói tin theo đường truyền tin i thì chi phí phải trả là sij (sij là số nguyên dương, sij ≤ 32767; i = 1, 2, ..., m; j = 1, 2, ..., n). Hãy xác định số lượng gói tin cần truyền theo mỗi đường truyền tin để việc truyền n gói tin được thực hiện với tổng chi phí phải trả là nhỏ nhất. 9 Dữ liệu: Dòng đầu tiên chứa hai số nguyên dương n và m (n , m ≤ 100); Dòng thứ i trong số m dòng tiếp theo chứa n số nguyên dương si1 si2 ... sin, i = 1, 2, ..., m. Kết quả: Dòng đầu tiên chứa S là tổng chi phí phải trả theo cách truyền tin tìm được; Dòng thứ hai chứa m số nguyên không âm q1 q2 ... qm, trong đó qi là số gói tin cần truyền theo đường truyền tin i. Ví dụ: ttin.in 3 3 20 20 20 4 3 10 1 3 20 ttin.out 4 0 2 1 6. Coin Giả sử tại một lúc nào đó bạn có N loại tiền kim loại (dạng đồng xu) được đánh số từ 1 đến N, mỗi loại có số lượng đồng không giới hạn. Mỗi đồng của loại tiền kim loại thứ i mang giá trị vi xu và có trọng lượng wi gam. Vì các loại tiền được đúc bằng các kim loại khác nhau nên có thể có những loại tiền cùng giá trị hoặc cùng trọng lượng nhưng không thể đồng thời có cùng giá trị và trọng lượng. Trong số N loại tiền của bạn, hãy chọn ra một số ít nhất M các đồng, sao cho chúng có tổng giá trị là V xu và tổng trọng lượng là W gam. M sẽ nhận giá trị 0 nếu không có cách chọn các đồng tiền thoả mãn hai giá trị V và W. Dữ liệu: Dòng đầu tiên chứa 3 số tự nhiên N, V, W (1 ≤ N ≤ 20; 1 ≤ V, W ≤ 150); N dòng tiếp theo, dòng thứ i chứa cặp số (vi, wi) là thông tin về một đồng của loại tiền thứ i (1 ≤ vi, wi ≤ 150). Kết quả: Nếu không tìm được cách thoả mãn thì chỉ ghi vào file ra số 0. Ngược lại, ghi ra file ra: Dòng 1: Ghi số M thoả mãn yêu cầu đặt ra; Dòng 2: Ghi N số nguyên không âm, trong đó số thứ i cho biết số đồng được chọn của loại tiền thứ i. Các số viết cách nhau bởi một dấu cách. Nếu có nhiều lời giải, hãy đưa ra lời giải nhỏ nhất theo thứ tự từ điển. Ví dụ: coin.in 8 141 4 1 1 2 1 4 1 8 1 16 1 32 1 64 1 128 1 4 11 17 12 34 7 8 10 21 9 10 coin.out 4 1 0 1 1 0 0 0 1 0 7. Chiếc túi xách Một người đi du lịch có n loại đồ vật có trọng lượng và giá trị khác nhau. Nhưng anh ta chỉ có một túi xách có dung lượng w (có thể chứa được một số đồ vật sao cho tổng trọng lượng của các đồ vật này nhỏ hơn hoặc đúng bằng w). Bạn hãy viết chương trình giúp người đi du lịch phải chọn lựa một danh sách các đồ vật mang đi như thế nào để tổng giá trị đồ vật mang đi là lớn nhất. Giả thiết mỗi loại đồ vật có đủ nhiều. Dữ liệu: File vào gồm 3 dòng. Dòng đầu tiên của file vào chứa hai số nguyên dương n và w (n, w ≤ 1000). Dòng thứ hai ghi n số nguyên dương ai (ai < 1000, i = 1, 2, ..., n). Dòng cuối cùng ghi n số nguyên dương ci (ci < 100.000, i = 1, 2, ..., n). Các số trên một dòng cách nhau bởi một dấu cách. Kết quả: File ra gồm 2 dòng. Dòng thứ nhất ghi tổng giá trị đồ vật mang đi lớn nhất. Dòng thứ hai ghi n số nguyên cách nhau bởi dấu cách, trong đó số thứ i là số lượng đồ vật i cần mang theo (i = 1, 2, ..., n). Nếu có nhiều cách mang đồ vật đều cho tổng giá trị lớn nhất thì ghi ra một cách bất kỳ trong chúng. Ví dụ: tuixach.in 5 20 1 2 3 4 6 1 2 9 8 16 tuixach.out 56 2 0 6 0 0 11 ... khóa thuật toán quy hoạch động việc xây dựng toán mà ta gọi mảng quy hoạch động Mảng 1, nhiều chiều tùy thuộc vào lời giải toán phụ thuộc vào loại tham số Tiếp đến cách quy nạp thu gọn toán sau... begin doc; xuli; ghi; end Thuật toán quy hoạch động mảng hai chiều Chúng ta gặp toán mà mảng quy hoạch động có kích thước lớn hơn: 2, 3, … chiều, chẳng hạn toán Bài toán Cho dãy số nguyên a1,... toán trở thành phần toán lớn Thuật toán quy hoạch động thường áp dụng để giải toán tối ưu, toán đếm, … Vì vậy, giới hạn kích thước liệu toán tối ưu lớn việc sử dụng thuật toán khác (như duyệt,

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