Tải bản đầy đủ (.doc) (95 trang)

Tài liệu ôn tập tin học lớp 12 kiểm tra, thi bồi dưỡng học sinh tham khảo (3).DOC

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (384.39 KB, 95 trang )

Một số vấn đề chọn lọc môn Tin học
I. Quy hoạch động
1. Phơng pháp quy hoạch động
2. Các bớc thực hiện
3. Hạn chế của quy hoạch động
4. Một vài ví dụ
II. Một số bài toán tiêu biểu
(Phát biểu, phân tích thuật toán và tổ chức dữ liệu, chơng trình)

III. Các bài tập luyện tập
1. Đề bài
2. Hớng dẫn
IV. Các đề tự giải
I. quy họach động
1. Phơng pháp quy hoạch động
Phơng pháp quy hoạch động cùng nguyên lý tối u đợc nhà toán học Mỹ
R.Bellman đề xuất vào những năm 50 của thế kỷ 20. Phơng pháp này đã đợc áp
dụng để giải hàng loạt bài toán thực tế trong các quá trình kỹ thuật công nghệ, tổ
chức sản xuất, kế hoạch hoá kinh tế Tuy nhiên cần lu ý rằng có một số bài toán
mà cách giải bằng quy hoạch động tỏ ra không thích hợp.
Trong thực tế, ta thờng gặp một số bài toán tối u loại sau: Có một đại lợng f
hình thành trong một quá trình gồm nhiều giai đoạn và ta chỉ quan tâm đến kết
quả cuối cùng là trị của f phải lớn nhất hoặc nhỏ nhất, ta gọi chung là giá trị tối u
của f. Giá trị của f phụ thuộc vào những đại lợng xuất hiện trong bài toán mà mỗi
bộ giá trị của chúng đợc gọi là một trạng thái của hệ thống và cũng phụ thuộc vào
cách thức đạt đợc giá trị f trong từng giai đoạn mà mỗi cách thức đợc gọi là một
điều khiển. Đại lợng f thờng đợc gọi là hàm mục tiêu và quá trình đạt đợc giá trị
tối u của f đợc gọi là quá trình điều khiển tối u.
Quy hoạch động
1
Một số vấn đề chọn lọc môn Tin học


Bellman phát biểu nguyên lý tối u (cũng còn gọi là nguyên lý Bellman) nh sau:
" Với mỗi quá trình điều khiển tối u, đối với trạng thái bắt đầu A
0
, nếu giữa chừng
ta đi đến một trạng thái A nào đó thì phần quá trình đó kể từ trạng thái A xem nh
trạng thái bắt đầu cũng là tối u."
Chú ý rằng nguyên lý này đợc thừa nhận và không chứng minh.
Phơng pháp tìm điều khiển tối u theo nguyên lý Bellman thờng đợc gọi là quy
hoạch động. Thuật ngữ này nói lên đợc thực chất của quá trình điều khiển là động:
có thể trong một số bớc đầu tiên lựa chọn điều khiển tối u dờng nh không tốt nhng
tựu chung cả quá trình lại là tốt nhất.
Ta có thể giải thích ý này qua bài toán sau:
Cho một dãy N số nguyên A
1
, A
2
, , A
N
. Hãy tìm cách xoá đi một số ít nhất số
hạng để dãy còn lại là đơn điệu hay tơng đơng hãy chọn một số nhiều nhất các số
hạng sao cho dãy B gồm các số hạng đó theo trình tự xuất hiện trong dãy A là đơn
điệu.
Quá trình chọn dãy B đợc điều khiển qua N giai đoạn để đạt đợc mục tiêu là số
lợng số hạng của dãy B là nhiều nhất, điều khiển ở giai đoạn i thể hiện việc chọn
hay không chọn A
i
vào dãy B.
Giả sử dãy đã cho là 1 8 10 2 4 6 7. Nếu ta chọn lần lợt 1, 8, 10 thì chỉ
chọn đợc 3 số hạng nhng nếu bỏ qua 8 và 10 thì ta chọn đợc 5 số hạng 1, 2, 4, 6, 7
.

Khi giải một số bài toán bằng cách chia để trị , chuyển việc giải bài toán
kích thớc lớn về việc giải nhiều bài toán cùng kiểu có kích thớc nhỏ hơn. Các thuật
toán này thờng đợc thể hiện bằng các chơng trình con đệ quy. Khi đó, trên thực tế,
nhiều kết quả trung gian phải tính nhiều lần.
Vậy ý tởng cơ bản của quy hoạch động thật đơn giản: tránh tính toán lại mọi
thứ hai lần, mà lu giữ kết qủa đã tìm kiếm đợc vào một bảng làm giả thiết cho việc
tìm kiếm những kết quả của trờng hợp sau. Chúng ta sẽ làm đầy dần giá trị của
bảng này bởi các kết quả của những trờng hợp trớc đã đợc giải. Kết quả cuối cùng
chính là kết quả của bài toán cần giải. Nói cách khác phơng pháp quy hoạch động
đã thể hiện sức mạnh của nguyên lý chia để trị đến mức cực độ.
Quy hoạch động
2
Một số vấn đề chọn lọc môn Tin học
Quy hoạch động là kỹ thuật thiết kế bottom-up (từ dới lên). Nó đợc bắt đầu với
những trờng hợp con nhỏ nhất (thờng là đơn giản nhất và giải đợc ngay). Bằng
cách tổ hợp các kết quả đã có (không phải tính lại) của các trờng hợp con, sẽ đạt
tới kết quả của trờng hợp có kích thớc lớn dần lên và tổng quát hơn, cho đến khi
cuối cùng đạt tới lời giải của trờng hợp tổng quát nhất.
Trong một số trờng hợp, khi giải một bài toán A, trớc hết ta tìm họ bài toán
A(p) phụ thuộc tham số p (có thể p là một véc tơ) mà A(p
0
)=A với p
0
là trạng thái
ban đầu của bài toán A. Sau đó tìm cách giải họ bài toán A(p) với tham số p bằng
cách áp dụng nguyên lý tối u của Bellman. Cuối cùng cho p=p
0
sẽ nhận đợc kết
quả của bài toán A ban đầu.
2. Các bớc thực hiện quy hoạch động

Bớc 1: Lập hệ thức
Dựa vào nguyên lý tối u tìm cách chia quá trình giải bài toán thành từng giai
đoạn sau đó tìm 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 đó. Hoặc tìm cách phân rã bài toán thành các "bài toán
con" tơng tự có kích thớc nhỏ hơn, tìm hệ thức nêu quan hệ giữa kết quả bài
toán kích thớc đã cho với các kết quả của các "bài toán con" cùng kiểu có kích
thớc nhỏ hơn của nó nhằm xây dựng phơng trình truy toán (dạng hàm hoặc
thủ tục đệ quy)
.Về một cách xây dựng phơng trình truy toán:
Ta chia việc giải bài toán thành N giai đoạn. Mỗi giai đoạn i có trạng thái
ban đầu của nó là t(i) và chịu tác động điều khiển d(i) sẽ biến thành trạng thái
tiếp theo t(i+1) của giai đoạn i+1 (i=1,2, ,n-1). Theo nguyên lý tối u của
Bellman thì việc tối u giai đoạn cuối cùng không làm ảnh hởng đến kết quả
toàn bài toán. Với trạng thái ban đầu là t(N) sau khi làm giai đoạn N tốt nhất
ta có trạng thái ban đầu của giai đoạn N-1 là t(N-1) và tác động điều khiển của
giai đoạn N-1 là d(N-1), có thể tiếp tục xét đến giai đoạn N-1. Sau khi tối u
giai đoạn N-1 ta lại có t(N-2) và d(N-2) và lại có thể tiến hành tối u giai đoạn
N-2 cho đến khi các giai đoạn từ N giảm đến 1 đợc tối u thì coi nh hoàn
Quy hoạch động
3
Một số vấn đề chọn lọc môn Tin học
thành bài toán. Gọi giá trị tối u của bài toán tính đến giai đoạn k là F
k
, giá trị
tối u của bài toán tính riêng ở giai đoạn k là G
k
thì
F
k
= F

k-1
+ G
k
Hay là:
F
k
(t(k)) = Max { G
k
(t(k), d(k)) + F
k-1
(t(k-1))} (*)
d(k)
Bớc 2: Tổ chức dữ liệu và chơng trình
Tổ chức dữ liệu sao cho đạt các yêu cầu sau:
a- Dữ liệu đợc tính toán dần theo từng bớc
b- Dữ liệu đợc lu trữ để giảm lợng tính toán lặp lại.
c- Kích thớc miền nhớ dành cho lu trữ dữ liệu càng nhỏ càng tốt, kiểu dữ liệu đợc
chọn phù hợp, nên chọn đơn giản dễ truy cập.
Cụ thể:
Các giá trị của F
k
thờng đợc lu trữ trong một bảng (mảng một chiều hoặc hai,
ba v.v chiều).
Cần lu ý khởi trị các giá trị ban đầu của bảng cho thích hợp, đó là các kết quả
của các bài toán con có kích cỡ nhỏ nhất của bài toán đang giải.
F
1
(t(1)) = Max { G
1
(t(1),d(1)) + F

0
(t(0))}
D(1)
Dựa vào công thức, phơng trình truy toán (*) và các giá trị đã có trong bảng để
tìm dần các giá trị còn lại của bảng.
Ngoài ra còn cần mảng lu trữ nghiệm tơng ứng với giá trị tối u trong từng giai
đoạn
Dựa vào bảng lu trữ nghiệm và bảng giá trị tối u từng giai đoạn đã xây dựng,
tìm ra kết quả bài toán.
Bớc 3: Làm tốt
Quy hoạch động
4
Một số vấn đề chọn lọc môn Tin học
Làm tốt thuật toán bằng cách thu gọn hệ thức (*) và giảm kích thớc miền
nhớ. Thờng tìm cách dùng mảng 2 một chiều thay cho mảng hai chiều nếu giá trị
một dòng (hoặc cột) của mảng hai chiều chỉ phụ thuộc một dòng (hoặc cột) kề tr-
ớc.
Trong một số trờng hợp có thể thay mảng 2 chiều với các giá trị phần tử chỉ
nhận giá trị 0, 1 bởi mảng 2 chiều mới bằng cách dùng kỹ thuật quản lý bít.
3. Hạn chế của quy hoạch động
Việc tìm công thức, phơng trình truy toán hoặc tìm cách phân rã bài toán nhiều
khi đòi hỏi sự phân tích tổng hợp rất công phu, dễ sai sót, khó nhận ra nh thế
nào là thích hợp, đòi hỏi nhiều thời gian suy nghĩ. Đồng thời không phải lúc
nào kết hợp lời giải của các bài toán con cũng cho kết quả của bài toán lớn
hơn.
Khi bảng lu trữ đòi hỏi mảng hai, ba chiều thì khó có thể xử lý dữ liệu với
kích cỡ mỗi chiều lớn hàng trăm.
Có những bài toán không thể giải dợc bằng quy hoạch động.

4. Một vài ví dụ

Ví dụ 1: Tính tổ hợp chập k của n.
Chúng ta có ngay công thức truy hồi quen thuộc là:
Nếu chúng ta tính tổ hợp chập k của n trực tiếp bằng hàm:
Function C(n,k)
If (k=0) or (k=n) then C:= 1
Else C:= C(n-1,k-1)+C(n-1,k).
Quy hoạch động
5



=
<<+
=



nk
nkCC
C
k
n
k
n
k
n
,0 1
0
1
1

1
Một số vấn đề chọn lọc môn Tin học
thì nhiều lần sẽ phải tính đi tính lại giá trị C(i,j) (i<n) (j<k). Do đó thời gian thực
hiện của thuật toán này lớn theo sự lặp lại. Chúng ta cũng gặp hiện tợng tơng tự
khi tính dãy số Fibonacci.
Ngợc lại nếu sử dụng bảng chứa các kết quả trung gian (bảng có dạng tam giác
Pascal) chúng ta sẽ đạt đợc một thuật toán hiệu suất hơn. Bảng sẽ đợc làm đầy dần
theo từng dòng.
0 1 2 3 k-1 k
0 1
1 1 1
2 1 2 1
n-1 C(n-1,k-1) C(n-1,k)
+
n C(n,k)
Cũng có thể chỉ cần dùng một véc tơ dài là k, véc tơ này biểu diễn cho dòng
hiện thời (dòng thứ n+1) của tam giác Pascal tính đến cột k+1 và chúng ta sẽ cập
nhật các giá trị vào nó từ trái qua phải. Do vậy thuật toán đợc thực hiện trong thời
gian O(n.k) và chiếm không gian O(k) nếu coi phép cộng là phép toán cơ bản:
Ch ơng trình :
uses crt;
const max = 20;
var n i,j,k : byte;
C : array[0 max] of longint;
p1,p2 : longint;

BEGIN
clrscr;
write('n, k ='); readln(n,k);
C[0] := 1;{C(0,1)=1}

C[1] := 1;{C(1,1)=1}
for i:=2 to n do
begin
Quy hoạch động
6
Một số vấn đề chọn lọc môn Tin học
p1 := 1;
for j:=1 to i-1 do
begin
p2 := C[j];
C[j] := p1 + p2;
p1 := p2;
end;
C[i] := 1;
end;
write(f,C[k],' ');
close(f);
END.
Ví dụ 2: Tính số Catalan Phát biểu bài toán: Xét tích các số M
i
(i=1,2, ,n)
là: M=M
1
.M
2
M
n
. Hỏi có bao nhiêu cách chèn cặp dấu ngoặc đơn vào tích này để
đợc các cách biểu diễn khác nhau của tích này?
Cụ thể: Tích ABCD có 5 cách đặt ngoặc khác nhau:

((AB)C)D
(AB)(CD)
(A(BC))D
A((BC)D)
A(B(CD))
Phân tích bài toán: Gọi số cách đặt ngoặc trong trờng hợp có n thừa số là
T(n). Bài toán trở thành tìm cách tính T(n) khi biết n. Bài toán này cha cho trực
tiếp công thức truy toán.
Ta cần phải xây dựng công thức truy toán tính T(n).
Nhận thấy trong các cách đặt ngoặc luôn tồn tại một cách đặt dấu ngoặc chia
tích thành hai phần: phần trái có i thừa số, phần phải có n-i thừa số, với i = 1,
2, , n-1. Có T(i) cách đặt ngoặc cho phần bên trái và T(n-i) cách đặt ngoặc cho
phần bên phải nên có công thức:
Quy hoạch động
7
)1()().()(
1
1


=
=
n
i
inTiTnT
Một số vấn đề chọn lọc môn Tin học
Ngoài ra với điều kiện ban đầu T(1)=1, chúng ta có thể tính đợc giá trị của T
nh trong bảng sau:
N 1 2 3 4 5 10 15
T(n) 1 1 2 5 14 4862 2674440

Các giá trị của T(n) đợc gọi là các số Catalan.
Dựa vào công thức truy hồi (1) chúng ta tính T(n) bằng quy hoạch động. Giá
trị các phần tử của mảng T đợc xây dựng dần từ 1 đến n:
T[1] = 1;
Ch ơng trình :
{$E+,N+}
uses crt;
var t : array[1 100] of extended;
n : integer;
procedure tinh;
var i,j : integer;
begin
fillchar(t,sizeof(t),0);
t[1] := 1;
for i:=2 to n do
for j:=1 to i-1 do
t[i] := t[i]+t[j]*t[i-j];
end;
BEGIN
write('n=');readln(n);
tinh;
writeln(t[n]:0:0);
END.
Quy hoạch động
8
), ,2()().()(
1
1
nijiTjTiT
i

j
==


=
Một số vấn đề chọn lọc môn Tin học
Ví dụ 3: Tìm đờng đi ngắn nhất giữa các cặp hai đỉnh trên đồ thị n đỉnh,
có trọng số, không có chu trình âm (thuật toán Floyld).
Xây dựng mảng hai chiều A[1 N,1 N] với ý nghĩa giá trị cuối cùng tính
đợc của A[i,j] là độ dài đờng đi ngắn nhất từ đỉnh i tới đỉnh j. Đồng thời dùng
mảng G[1 N,1 N] với ý nghĩa G[i,j]=k nếu k là đỉnh trung gian mà đờng đi
ngắn nhất từ i tới j phải qua k, đó là đỉnh thoả mãn: A[i,k]+A[k,j]<A[i,j].
Nh vậy mỗi khi tìm đợc đỉnh k, bài toán đã đợc phân rã thành hai bài toán
tơng tự là tìm đờng đi ngắn nhất từ i đến k và tìm đờng đi ngắn nhất từ k đến j.
Ví dụ 4: Tìm đờng đi ngắn nhất từ đỉnh x đến đỉnh y trên đồ thị n đỉnh, có
trọng số không âm (thuật toán Dijkstra).
áp dụng nguyên lý quy hoạch động của Bellman bằng kỹ thuật gán nhãn
(xem chơng Đồ thị hữu hạn và các thuật toán cơ bản).
II. Một số bài toán tiêu biểu:
Bài 1: (Dãy con không giảm dài nhất)
Cho N số nguyên dơng (0<N10
4
) và một dãy A
1
, A
2
, ,

A
n

các số nguyên.
Tìm trong dãy đã cho một dãy con
thoả mãn các điều kiện:
a)
b) i
j
< i
j+1
c) k lớn nhất
Dữ liệu vào: File BL1.INP có cấu trúc nh sau:
+ Dòng thứ nhất ghi số N
Quy hoạch động
9
(*) ,,,,
321
i
A
i
A
i
A
i
A
k
i
A
i
A
jj 1+


Một số vấn đề chọn lọc môn Tin học
+ Các dòng tiếp theo chứa dãy A
1
, A
2
, ,

A
n
mỗi dòng 10 số (trừ dòng cuối
cùng có thể ít hơn 10 số), các số cách nhau ít nhất một dấu cách.
Dữ liệu ra : File BL1.OUT có cấu trúc nh sau:
+ Dòng thứ nhất ghi số k
+ Các dòng tiếp theo chứa k số A
i1
, A
i2
, , A
ik
mỗi dòng10 số (trừ dòng cuối
cùng có thể ít hơn 10 số), các số cách nhau ít nhất một dấu cách.
Hớng dẫn: Xây dựng mảng T và mảng D với ý nghĩa:
T[i]=j là chỉ số j (trong dãy (*)) của phần tử đứng ngay trớc A
i
trong dãy kết
quả. Cách tính T[i]: duyệt mảng A từ vị trí 1 đến vị trí i-1, tìm vị trí j có D[j] lớn
nhất trong số các vị trí j thoả mãn A[j]A[i].
D[i] là độ dài của dãy kết quả khi bài toán chỉ xét dãy A
1
, A

2
, ,

A
i
và đợc tính
theo công thức truy hồi:
D[i] = Max { D[j] +1 j mà j<i và A
j
A
i
}
Chú ý khởi trị: T[1]:= 0 ; D[1]:= 1; Ví dụ:
I 1 2 3 4 5 6 7 8 9 10 11 12
A[i] 6 12 8 11 3 4 1 7 5 9 10 2
T[i] 0 1 1 3 0 5 0 6 6 8 10 7
D[i] 1 2 2 3 1 2 1 3 3 4 5 2
Khi duyệt ngợc tìm kết quả ta tiến hành nh sau:
Tìm phần tử lớn nhất trong D, giả sử đó là D[i], ta đổi dấu của D[i] coi nh
đánh dấu nó, tìm tiếp phần tử j = T[i], lại đổi dấu D[j], quá trình cứ nh thế lùi chỉ
số j đến khi j=0
I 1 2 3 4 5 6 7 8 9 10 11 12
A[i] 6 12 8 11 3 4 1 7 5 9 10 2
T[i] 0 1 1 3 0 5 0 6 6 8 10 7
D[i] 1 2 2 3 -1 -2 1 -3 3 -4 -5 2
Quy hoạch động
10
Mét sè vÊn ®Ò chän läc m«n Tin häc
KÕt qña ®îc d·y con dµi nhÊt lµ : 3 4 7 9 10
Ch ¬ng tr×nh :

uses crt;
const max = 10000;
fi = 'BL1.INP';
fo = 'BL1.OUT';
type mang = array[1 max] of integer;
var a,d,t : mang;
n,dem : longint;
f : text;
procedure nhap;
var i: longint;
begin
fillchar(a,sizeof(a),0);
assign(f,fi);
reset(f);
readln(f,n);
for i:=1 to n do read(f,a[i]);
close(f);
end;
procedure khoitri;
begin
fillchar(t,sizeof(t),0);
t[1]:= 0;
d[1]:= 1;
end;
function vitri_truoc(i: longint): longint;
var j,ld,lj: longint;
begin
ld:= 0;
lj:= 0;
vitri_truoc:= 0;

for j:=i-1 downto 1 do
Quy ho¹ch ®éng
11
Mét sè vÊn ®Ò chän läc m«n Tin häc
if a[j]<=a[i] then
if d[j]>ld then
begin
ld:= d[j];
lj:= j;
end;
vitri_truoc:= lj;
end;
procedure tao_td;
var i: longint;
begin
khoitri;
for i:=2 to n do
begin
t[i]:= vitri_truoc(i);

if t[i]=0 then d[i]:= 1
else
d[i]:= d[t[i]]+1;
end;
end;
function maxd: longint;
var i,p,li: longint;
begin
p := -maxint;
li := 0;

for i:=1 to n do
if d[i]>p then
begin
p := d[i];
li := i;
end;
maxd:= li;
end;
Quy ho¹ch ®éng
12
Mét sè vÊn ®Ò chän läc m«n Tin häc
procedure timketqua;
var i: longint;
begin
i := maxd;
d[i] := -d[i];
dem := 1;
repeat
i:= t[i];
if i<>0 then
begin
d[i]:= -d[i];
inc(dem)
end;
until i=0;
end;
procedure ghi;
var f : text;
i : longint;
begin

assign(f,fo);
rewrite(f);
writeln(f,dem);
dem:= 0;
for i:= 1 to n do
if d[i]<0 then
begin
write(f,a[i]:7);
inc(dem);
if dem mod 10 = 0 then writeln(f);
end;
close(f);
end;
BEGIN
clrscr;
Quy ho¹ch ®éng
13
Một số vấn đề chọn lọc môn Tin học
nhap;
tao_td;
timketqua;
ghi;
END.
Bài 2: (Dãy chung dài nhất của 2 dãy số)
Cho 2 số nguyên dơng M, N (0<M, N<=100) và 2 dãy số nguyên: A
1
,
A
2
, ,


A
N
và B
1
, B
2
, ,

B
M
. Tìm một dãy dài nhất C nhận đợc từ A bằng cách xoá
đi một số số hạng và cũng nhận đợc từ B bằng cách xoá đi một số số hạng (nói
chung không cùng chỉ số nh đối với dãy A). Ta gọi C là dãy con chung dài nhất
của hai dãy A và B.
Dữ liệu vào: File BL2.INP có cấu trúc nh sau:
+ Dòng thứ nhất chứa N số A
1
, A
2
, ,

A
N
+ Dòng thứ hai chứa M số B
1
, B
2
, ,


B
M
.
Dữ liệu ra : File BL2.OUT có cấu trúc nh sau:
+ Dòng thứ nhất ghi số k là số số hạng của dãy C.
+ Dòng thứ hai chứa k số là các số hạng của dãy C.
+ Dòng thứ ba chứa k số là chỉ số trong dãy A của k số hạng của C
+ Dòng thứ t chứa k số là chỉ số trong dãy B của k số hạng của C
H ớng dẫn:
Cần xây dựng mảng C[1 N,1 M] với ý nghĩa: C[i,j] là độ dài của dãy
chung dài nhất của hai dãy A[1 i] và B[1 j]. Đơng nhiên C[1,j] = 0 nếu A[1]
không có trong dãy B, ngợc lại thì C[1,j] = 1. Tơng tự C[i,1] = 0 nếu B[1] không
có trong dãy A, ngợc lại thì C[i,1] = 1. Những trờng hợp còn lại C[i,j] đợc tính
theo công thức truy hồi sau:
C[i,j] = Max{C[i,j-1],C[i-1,j],C[i-1,j-1]+x}
(mà x=0 nếu A[i] B[j] và x=1 nếu A[i]=B[j])
Thật vậy:
Quy hoạch động
14
Mét sè vÊn ®Ò chän läc m«n Tin häc
NÕu A[i]=B[j] th× C[i,j] = C[i-1,j-1] +1
NÕu A[i]<>B[j] th×
+ NÕu A[i] trong B[1 j] th× nã chØ thuéc B[1 j-1] nªn C[i,j] = C[i,j-1]
+ NÕu B[j] trong A[1 i] th× nã chØ thuéc A[1 i-1] nªn C[i,j] = C[i-1,j]
Ch ¬ng tr×nh :
uses crt;
const fi = 'BL2.INP';
fo = 'BL2.OUT';
type mang = array[1 100] of integer;
m2 = array[1 100,1 100] of integer;

var f : text;
a,b : mang;
nh : m2;
m,n : byte;
pa,pb : mang;
dem : byte;
procedure doc_file;
var f : text;
begin
m := 0;
n := 0;
assign(f,fi);
reset(f);
while not eoln(f) do
begin
inc(m);
read(f,a[m]);
end;
readln(f);
while not eoln(f) do
begin
inc(n);
read(f,b[n]);
Quy ho¹ch ®éng
15
Mét sè vÊn ®Ò chän läc m«n Tin häc
end;
close(f);
end;
function thuoc(ch : integer;x : mang;k : byte) : boolean;

var i : byte;
begin
for i:=1 to k do
if ch = x[i] then
begin
thuoc := true;
exit;
end;
thuoc := false;
end;
function max(i,j,k : integer) : integer;
var p : integer;
begin
p := i;
if j>p then p := j;
if k>p then p := k;
max := p;
end;
procedure thuc_hien;
var i,j : byte;
begin
for i:=1 to m do
if thuoc(b[1],a,i) then
nh[i,1] := 1 else nh[i,1] := 0;
for j:=1 to n do
if thuoc(a[1],b,j) then
nh[1,j] := 1 else nh[1,j] := 0;
for i:=2 to m do
for j:=2 to n do
nh[i,j] := max(nh[i-1,j-1]+ord(a[i]=b[j]),

Quy ho¹ch ®éng
16
Mét sè vÊn ®Ò chän läc m«n Tin häc
nh[i,j-1],nh[i-1,j]);
writeln(f,'do dai 2 day sau khi xoa : ',nh[m,n]);
i := m;
j := n;
fillchar(pa,sizeof(pa),0);
fillchar(pb,sizeof(pb),0);
dem := 0;
while (i>0) and (j>0) do
begin
if a[i]=b[j] then
begin
inc(dem);
pa[dem] := i;
pb[dem] := j;
dec(i);
dec(j);
end
else
if nh[i,j]=nh[i,j-1] then dec(j)
else dec(i);
end;
for i:=dem downto 1 do write(f,a[pa[i]],' ');
writeln(f);
for i:=dem downto 1 do write(f,pa[i],' ');
writeln(f);
for i:=dem downto 1 do write(f,pb[i],' ');
end;

BEGIN
clrscr;
assign(f,fo);
rewrite(f);
doc_file;
thuc_hien;
close(f);
Quy ho¹ch ®éng
17
Một số vấn đề chọn lọc môn Tin học
END.
Bài 3: (Di chuyển từ Tây sang Đông)
Cho hình chữ nhật MìN ô vuông, mỗi ô chứa 1 số nguyên. Có thể di
chuyển từ 1 ô sang ô thuộc cột bên phải cùng dòng hoặc chênh lệch 1 dòng. Tìm
cách di chuyển từ một ô nào đó của cột 1 đến một ô nào đó thuộc cột n sao cho
tổng các số của các ô đi qua là nhỏ nhất.
Dữ liệu vào lấy từ file BL3.INP dòng đầu là 2 số nguyên dơng M, N. M
dòng tiếp theo mỗi dòng N số nguyên của hình chữ nhật.
Kết quả ghi ra file BL3.OUT gồm 2 dòng:
Dòng thứ nhất ghi tổng các số của các ô đi qua.
Dòng thứ hai ghi N số là chỉ số dòng của các ô đi qua từ cột 1 đến cột N.
H ớng dẫn:
Giả sử các số cho trong mảng A[1 M,1 N]. Dùng mảng F[1 M,1 N]
để xây dựng nhãn cho từng ô theo công thức truy hồi. F[i,j] có giá trị bằng tổng
các số trên các ô đi qua theo con đờng tốt nhất từ một ô thích hợp thuộc cột 1 đến
ô (i,j) thuộc dòng i cột j.
Nhãn của các ô thuộc cột 1 bằng chính giá trị các ô đó. Các ô còn lại, lần lợt từ
cột 2 đến cột n đợc xây dựng theo công thức truy hồi sau:
F[i,k] := Min { F[i-1,k-1], F[i,k-1], F[i+1,k-1] } + A[i,k]
Ngoài ra, dùng mảng hai chiều T[1 M,1 N] để ghi lại chỉ số dòng của ô

thuộc cột j-1 đi tới ô (i,j) và mảng một chiều KQ[1 N] để ghi lại chỉ số dòng của
các ô đi qua từ cột 1 đến cột n trong phơng án tối u.
Cũng lu ý rằng có thể không cần dùng mảng F[1 M,1 N] bằng cách ghi
giá trị của F[1 M,1 N] đè dần lên mảng A[1 M,1 N] bắt đầu từ cột 2 đến cột
N.
Quy hoạch động
18
Mét sè vÊn ®Ò chän läc m«n Tin häc
uses crt;
const maxmn = 100;
fi = 'BL3.INP';
fo = 'BL3.OUT';
var a,t : array[0 maxmn,0 maxmn] of integer;
kq : array[1 maxmn] of byte;
m,n : byte;
procedure doc_file;
var f : text;
i,j : byte;
begin
assign(f,fi);
reset(f);
readln(f,m,n);
for i:=1 to m do
begin
for j:=1 to n do read(f,a[i,j]);
readln(f);
end;
close(f);
end;
function min(i,j : byte): byte;

var p : integer; d : byte;
begin
p := a[i-1,j-1];
d := i-1;
if a[i,j-1]<p then
begin
p := a[i,j-1];
d := i;
end;
if a[i+1,j-1]<p then
begin
p := a[i+1,j-1];
Quy ho¹ch ®éng
19
Mét sè vÊn ®Ò chän läc m«n Tin häc
d := i+1;
end;
min := d;
end;
procedure tao_nhan;
var i,j,d : byte;
begin
for j:=0 to n do a[0,j] := maxint;
for j:=0 to n do a[m+1,j] := maxint;
fillchar(t,sizeof(t),0);
for j:=2 to n do
for i:=1 to m do
begin
d := min(i,j);
a[i,j] := a[d,j-1] + a[i,j];

t[i,j] := d;
end;
end;
procedure tim_duong;
var i,j,d : byte;
p : integer;
f : text;
begin
p := maxint;
for i:=1 to m do
if a[i,n]<p then
begin
d := i;
p := a[i,n];
end;
j := n;
i := d;
kq[j] := d;
Quy ho¹ch ®éng
20
Một số vấn đề chọn lọc môn Tin học
assign(f,fo);
rewrite(f);
writeln(f,a[i,j]);
while j>0 do
begin
i := t[i,j];
j := j-1;
kq[j] := i;
end;

for j:=1 to n do write(f,kq[j],' ');
close(f);
end;
BEGIN
doc_file;
tao_nhan;
tim_duong;
END.
Bài 4a: (Xếp va li)
Cho một va ly có thể chứa W đơn vị trọng lợng. Có N loại đồ vật (số lợng mỗi
đồ vật không hạn chế), đồ vật i có trọng lợng A[i] và có giá trị là C[i]. Hỏi nên
Quy hoạch động
21
Một số vấn đề chọn lọc môn Tin học
chọn mỗi loại đồ vật bao nhiêu xếp vào va ly để tổng giá trị của va ly là lớn
nhất.
Dữ liệu vào lấy từ file văn bản VALY.INP gồm ba dòng
Dòng thứ nhất là N và W
N dòng tiếp theo: dòng i+1 ghi hai số: A[i] và C[i] (i=1,2, N), hai số cách
nhau bởi dấu cách.
Kết quả ghi ra file văn bản VALY.OUT theo quy cách sau:
Dòng thứ nhất là tổng giá trị lớn nhất của va ly
Các dòng tiếp theo mỗi dòng 2 số: số i (số hiệu vật đợc chọn) và số x (số lợng
chọn vật i)
Ví dụ:
Valy.inp
4 100
50 50
19 20
80 90

21 25
valy.out
110
2 1
3 1
H ớng dẫn:
a) Tổ chức dữ liệu:
Hai mảng một chiều g1 và g2: g1[y] là tổng giá trị các vật đã đợc chọn khi
trọng lợng còn thiếu của va ly là y và vừa xét xong đồ vật có số hiệu lẻ,
g2[y] có ý nghĩa tơng tự khi vừa xét xong đồ vật có số hiệu chẵn.
Hai mảng một chiều v1 và v2: v1[y] là số hiệu đồ vật đợc chọn cuối cùng
khi trọng lợng còn thiếu của va ly là y và vừa xét xong vật có số hiệu lẻ,
v2[y] là số hiệu đồ vật đợc chọn cuối cùng khi trọng lợng còn thiếu của va
ly là y và vừa xét xong vật có số hiệu chẵn.
b) Thực hiện: Để diễn đạt khi không phân biệt g1, g2 ta tạm dùng ký hiệu g,
không phân biệt v1, v2 ta dùng ký hiệu v.
Quy hoạch động
22
Một số vấn đề chọn lọc môn Tin học
Khởi trị g[0]=0,v[0]=0, g1[i] bằng giá trị nhận đợc khi chọn một lợng tối
đa đồ vật 1 cho vào va ly có trọng lợng còn thiếu là i (lu ý số hiệu đồ vật 1
là k=1 là số lẻ); v1[i]=1 nếu chọn đợc ít nhất một đồ vật 1 cho vào va ly có
trọng lợng còn thiếu là i.
Sau đó xét chọn tiếp các đồ vật từ số hiệu k=2 đến n cho vào va ly còn
thiếu trọng lợng y nếu thấy lợi theo công thức gán nhãn sau:
Tìm kết quả: nếu N chẵn thì lần ngợc theo g2 và v2, nếu N lẻ theo g1 và
v1. Kết quả số hiệu các đồ vật cho vào va ly đợc ghi nhận vào mảng một
chiều x: với ý nghĩa x[j] là số lợng đồ vật có số hiệu j đợc chọn vào va ly.
Ghi chú: Tuy nhiên bài toán này còn có thể giải bằng thuật toán có hiệu quả hơn
về thời gian thực hiện cũng nh kích thớc bộ nhớ so với thuật toán vừa nêu (xem ch-

ơng xếp lịch công việc)
Ch ơng trình:
uses crt;
const fi = 'valy.in3';
fo = 'valy.ou3';
var
a, {Trọng lợng vật i : a[i]}
c, {Giá trị vật i : c[i]}
Quy hoạch động
23



+
>
=
ykaygkaygkc
ykakhiyg
yg
][)][1,]][[2][max(
][ ][1
][2



<
=
=
][2][1
][2][1 ][1

][2
ygygk
ygygkhiyv
yv



<
=
=
][2][1
][2][1 ][2
][1
ygygk
ygygkhiyv
yv



+
>
=
ykaygkaygkc
ykakhiyg
yg
][)][2,]][[1][max(
][][2
][1
Một số vấn đề chọn lọc môn Tin học
w, {Trọng lợng tối đa của va ly}

n : longint; {Số đồ vật}
sum_max : longint; {Tổng giá trị chọn đợc}
g1,g2:array[0 1500] of integer; {Theo rõi tổng giá trị chọn}
v1,v2:array[0 10000] of integer; {Số hiệu vật chọn}
x : array[1 1500] of integer;{x[i]: Số lợng vật i đợc chọn}
procedure input;
var f : text;
i : integer;
begin
assign(f,fi);
reset(f);
readln(f,n,w);
for i:=1 to n do
read(f,a[i],c[i]);
close(f);
end;
function max(a,b:longint):longint;
begin
if a>=b then max:=a
else max:=b;
end;
procedure tinh2(k,y:integer);{k=2,4,6, > tạo g2 từ g1, v2 từ v1}
begin
if a[k]>y then
g2[y]:=g1[y] {không chọn vật k, g2 lấy lại giá trị g1}
else
g2[y]:=max(c[k]+g2[y-a[k]], g1[y]);{có thể chọn k, hoặc không}
if g1[y]=g2[y] then {không chọn vật k}
v2[y]:=v1[y]; {ghi lại vật chọn ở bớc trớc}
if g1[y]<g2[y] then {chọn vật k}

v2[y]:=k; {ghi lại vật vừa chọn là k}
end;
Quy hoạch động
24
Một số vấn đề chọn lọc môn Tin học
procedure tinh1(k,y:integer);{k =3,5,7 > tạo g1 từ g2, v1 từ v2}
begin {quá trình tơng tự thủ tục trên}
if a[k]>y then g1[y]:=g2[y]
else
g1[y]:=max(g2[y],c[k]+g1[y-a[k]]);
if g2[y]=g1[y] then v1[y]:=v2[y];
if g2[y]<g1[y] then v1[y]:=k;
end;
procedure qhd;
var i,k,y,cs,s,j:integer;
begin
(* Khởi tạo *)
g1[0] := 0;
g2[0] := 0;
v1[0] := 0;
v2[0] := 0;
for i:=1 to w do {các khả năng về trọng lợng còn thiếu của va ly}
begin
g1[i] := c[1]*(i div a[1]);
if g1[i] >0 then
v1[i] := 1{chọn vật 1, số lợng là i div a[1]}
else v1[i]:=0;
end;
for k:=2 to n do {Xét chọn các vật từ 2->n}
begin

if (k mod 2)=0 then
for y:=1 to w do tinh2(k,y)
{Khi va ly còn thiếu trọng lợng y, xét chọn vật k chẵn, xây dựng g2,v2}
else
for y:=1 to w do tinh1(k,y);
{Khi va ly còn thiếu trọng lợng y, xét chọn vật k lẻ, xây dựng g1,v1}
end;
(* Tìm ngợc: tìm phơng án tối u *)
for i:=1 to n do x[i]:=0;
Quy hoạch động
25

×