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

CHUYÊN đề TIN học QUY HOẠCH ĐỘNG

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 (387.64 KB, 48 trang )

Nhời nói đầu :
Quy hoạch động là một phơng pháp hữu hiệu để giải quyết một bài toán tối u.
Những bài giải bằng QHĐ đều cho kết quả tốt về cả đáp số lẫn thời gian. Nhng để
phát hiện ra và cài đặt tốt một bài quy hoạch động là rất khó khăn. Thờng thì
chúng ta hay tiếp cận với những bài toán QHĐ mà đọc lên đã có ngay dạng hay
phơng pháp giải, nhng nh vậy là cha đủ bởi lẽ QHĐ không dừng lại ở đó. Chúng
ta chỉ có thể giác ngộ t tởng để giải một bài QHĐ chứ chúng ta không thể học hết
đợc toàn bộ mọi phơng pháp quy hoạch. tập bài này cũng vậy, có lẽ nó cũng chỉ
cho ta biết và hình dung nho nhỏ về một số phuơng pháp QHĐ và những kinh
nghiệm khi làm một bài toán quy hoạch mà tôi rút ra qua quá trình học tập v
giảng dạy. Tập QHĐ này gồm các phần :
Phần 1: Một số kinh nghiệm khi làm QHĐ
Phần 2: Một số bài toán QHĐ cơ bản
Phần 3: Các bài luyện về QHĐ
Phần 4: Hớng dẫn giải bài luyện QHĐ
Các bài tập một số thuộc quá trình học tập giảng dạy của tôi và một số tuyển chọn
từ một số sách, tạp chí tin học. Chắc chắn rằng tập bài này không thể hoàn thiện
và không tránh khỏi sai sót, xin đợc tiếp thu ý kiến đóng góp của các thầy, các
cô.

1


Phần 1 : một số kinh nghiệm khi làm quy hoạch động
QHĐ là một phơng pháp mạnh để giải các bài toán trong tin học. QHĐ đòi hỏi một khả
năng nhìn nhận và phân tích chi tiết một bài toán. Để có đợc nhiều kinh nghiệm giải
QHĐ thì không một cách nào khác là ta phải tiếp cận với càng nhiều càng tốt những bài
toán QHĐ. và theo tôi thì khuôn mẫu chung để làm quy hoạch động gồm ba bớc :
* Lập hệ thức : dựa vào nguyên lí tối u để chia bài toán thành giai đoạn làm việc. Sau đó
tìm hệ thức biểu diễn quan hệ giữa các bớc đang xử lí với các bớc đã xử lí trớc đó hoặc
tìm cách phân rã thành những bài toán con nhỏ hơn và từ đó xây dựng đợc phơng trình


truy toán(dạng hàm hoặc thủ tục đệ quy)
* Tổ chức dữ liệu và chơng trình : tổ chức dữ liệu sao cho đạt yêu cầu sau:
+ dữ liệu đợc tính toán dần theo từng bớc
+ dữ liệu đợc lu trữ dể giảm lợng tính toán lặp lại
+ 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ải phù hợp dễ truy cập
* Làm tốt : làm tốt bằng cách thu hẹp hệ thức và giảm không gian nhớ cần sử dụng.
Tuy lí thuyết quy hoạch động rất đơn giản nh vậy nhng việc áp dụng nó vào một bài toán là
không hề dễ dàng bởi lẽ với mỗi bài toán đòi hỏi ta phải thiết lập đuợc một phơng trình truy
toán khác nhau, chính phơng trình truy toán đó thể hiện khả năng t duy sáng tạo của mỗi
ngời. Nói chung quy hoạch động là một phơng pháp đòi hỏi ta phải nhìn nhận bài toán cực
kì tinh tế và biết cách tổ chức dữ liệu hợp lí cộng với một phong cách lập trình tốt, không
làm đợc vậy thì việc giải một bài quy hoạch động phức tạp là vô cùng khó khăn. Trớc khi
làm quy hoạch động hãy suy nghĩ thật kĩ để tìm ra và xây dựng công trức truy hồi cho thật
chính xác và phải vạch ra đợc đờng lối làm việc đúng đắn và thông suốt, có vậy ta mới bắt
tay vào lập trình, nếu không chỉ cần một lỗi nhỏ trong quá trình lập trình sẽ khiến ta phải t
duy lại toàn bộ quá trình làm việc và cũng có thể bạn phải quay lại vị trí xuất phát và nh vậy
đơng nhiên bạn sẽ mất rất nhiều thời gian.
Còn đây là cách nhìn nhận phơng pháp quy hoạch động của bạn Phạm Hải Minh
Quy hoch ng l mt phng phỏp rt hay v mnh ca tin hc. Nhng gii c
cỏc bi toỏn bng phng phỏp quy hoch ng tht chng d dng chỳt no. Ch yu
hc sinh hin nay s dng quy hoch ng theo kiu lm tng bi cho nh mu v ỏp
dng vo nhng bi cú dng tng t.
Qua quỏ trỡnh hc tp v ging dy tụi ó t rỳt ra cho mỡnh mt s kinh nghim v cỏch
gii cỏc bi toỏn bng quy hoch ng, xin a ra mi ngi cựng tham kho v gúp
ý.
1. Lớ thuyt:
Phng phỏp quy hoch ng gm 6 bc:
- Bc 1: Chia nh bi toỏn
Lp vect P cú cỏc thnh phn x1,x2,..,xn. Mi vect P ng vi mt bi toỏn con ca bi

2


toỏn. Ban u ta xõy dng P vi 1 thnh phn duy nht.
- Bc 2: Lp h thc quy hoch ng
Xõy dng hm f(P) l hm ti u ca vect P (hay hm ti u cho mi bi toỏn con)
f(P) = g(f(P1),f(P2),..,f(Pn))
g cú th l hm Max,Min hoc tng tu yờu cu ca bi toỏn l tỡm Max,Min hay tớnh
tng.
P gi l vect cha
P1,P2,P3,..,Pn gi l vect con
- Bc 3: Kim tra
Nu khụng xõy dng c hm f thỡ thờm tip hoc b i tng thnh phn ca vect P
ri quay li bc 2. Nu c thỡ lm tip bc 4.
- Bc 4: Ti u hoỏ h thc
Ti u vect P bng cỏch xột tng thnh phn x ca vect P:
Chn vect PBest trong P1,P2,P3,..Pn ch khỏc nhau thnh phn x sao cho cú th a
PBest vo thay P1,P2,P3..,Pn trong hm g m khụng lm thay i giỏ tr ca hm g thỡ cú
th n gin thnh phn x ca vect P.
- Bc 5: Chn kiu quy hoch ng
+ Kiu 1: Nu cỏc thnh phn ca vect con P1 luụn hay cỏc thnh phn ca vect
cha P thỡ ta cú th dựng cỏc vũng lp for lng nhau ci t.
+ Kiu 2: Nu vect P v vect P1 luụn cú mi quan h cha con mt chiu thỡ ta cú th
dựng phng phỏp quy cú nh ci t.
+ Kiu 3: Nu vect P v vect P1 luụn cú mi quan h cha con hai chiu nhng khụng
rừ õu l vect cha , õu l vect con vỡ cũn ph thuc vo tng bi toỏn thỡ ta cú th
dựng phng phỏp repeat.. until ci t.
- Bc 6: Ti u hoỏ b nh (ch dựng cho ci t kiu 1)
n gin vect P bng cỏch xột tng thnh phn x ca vect P:
Nu f(P(..,x,.. ))=g(f(P1(..,x1,..)),f(P2(..,x2,..)),..,f(Pn(..,xn,..)))

v x-x1, x-x2,.., x-xnT no ú thỡ ta ch cn a vũng lp ca x lờn u tiờn v b x ra
khi vect P v lu T+1 vect P.
Tóm lại dù nói thể nào thì phơng pháp này chủ yếu đòi hỏi khả năng thiết lập một phơng
án chia nhỏ và phân rã bài toán cho tới khi vấn đề còn lại ta có thể giải quyết ngay tức thì.

Phần 2 : Một số bài toán quy hoach động cơ bản:
3


Bài1 : Dãy con tăng dài nhất : Cho dãy số nguyên n phần tử, hãy tìm dãy con tăng chặt dài nhất của
dãy đã cho ( các phần tử của dãy con có thể không liên tiếp nhau).
Dữ liệu vào file DCT.INP:
- dòng đầu tiên ghi số n (1<=n<=10000)
- dòng thứ i trong số n dong tiếp theo mỗi dòng ghi số ai (0<=ai<=30000)
Kết quả ra file DCT.OUT dòng đầu tiên ghi m là số lợng phần tử của dãy con tăng dài nhất tìm đợc. m dong sau mỗi dòng ghi một phần tử của dãy con tăng tìm đợc.
Ví dụ
DCT.INP DCT.OUT
6
4
1
1
5
2
2
3
8
7
3
7
Giải thuật : Gọi dãy ban đầu là a1,a2,...an đặt D[i] là độ dài lớn nhất của dãy con tìm đợc từ dãy bắt

đầu từ vị trí a1 kết thúc ở ai. nh vậy ta có hệ thức quy hoạch động : D[i]= Max(D[j]+1) (với
0<=j<=i-1 và D[i]>D[j] )
D[0]=0; a[0]= -maxint;
Ban đầu ta khởi tạo mảng D toàn các giá trị 0. Kết quả tìm đợc là Max(D[i] với 1<=i<=n). Để truy
vết và in ra dãy con tăng dài nhất ta dùng mảng Truoc với Truoc[i] là vị trí của phần tử truớc phần
tử i trong dãy con tối u đến vị trí i.
Chơng trình :
Uses crt;
Const infile
= 'DCT.INP';
outfile
= 'DCT.OUT';
maxn
= 10000;
Type M1
Var

= Array [0..Maxn] of integer;

a,d,Tr
: M1;
n,m
: integer;
f,g
: text;

procedure DocDl;
var i:integer;
begin
Assign(f,infile);

Reset(f);
Readln(f,n);
For i:=1 to n do
Readln(f,a[i]);
Close(f);
end;
Procedure ChuanBi;
begin
fillchar(D,sizeof(D),0);
fillchar(Tr,sizeof(Tr),0);
A[0]:=-maxint;

4


end;
Procedure XuLi;
var i,j:integer;
begin
For i:=1 to n do
For j:=i-1 downto 0 do
if (a[i]>a[j]) and (D[i]begin
D[i]:=D[j]+1;
Tr[i]:=j;
end;
end;
Procedure GhiKq;
var i,j,u,v,max,t:integer;
begin

Assign(g,outfile);
Rewrite(g);
max:=0;
for i:=1 to n do
if maxbegin
max:=d[i];
V:=i;
end;
T:=1;
While v<>0 do
begin
d[t]:=a[v];
inc(t);
v:=Tr[v];
end;
Writeln(g,max);
for i:=max downto 1 do
Writeln(g,D[i]);
Close(g);
end;
Begin
Clrscr;
DocDl;
ChuanBi;
XuLi;
Ghikq;
End.

Nh vậy với chơng trình trên ta đã tìm đợc dãy con tăng với mã phần tử và lu vào mảng D

trong thủ tục ghikq, làm nh vậy là tuân thủ đúng giải thuật đề ra ở trên nhng làm vậy là cha
hẳn tốt. Để làm tốt ta cần tìm ngợc lại từ n--->1 để tìm dãy con giảm nh vậy ta không cần lu
vào mảng D trong thủ tục ghikq nữa mà ta có thể in ra ngay kết quả là dãy con tăng trong
thủ tục ghikq. Ta tạo hai cận min và max ở hai đầu dãy là vị trí a[0] và vị trí a[n+1] nh vậy
kết quả tìm ra ngay tai vị trí 0. Chơng trình đã đợc cải tiến nh sau :
Uses crt;
Const infile
= 'DCT.INP';
outfile
= 'DCT.OUT';
maxn
= 10000;
Type M1
Var

= Array [0..Maxn+1] of integer;

a,d,Tr
: M1;
n,m
: integer;

5


f,g

: text;

procedure DocDl;

var i:integer;
begin
Assign(f,infile);
Reset(f);
Readln(f,n);
For i:=1 to n do
Readln(f,a[i]);
Close(f);
end;
Procedure ChuanBi;
begin
fillchar(D,sizeof(D),0);
fillchar(Tr,sizeof(Tr),0);
A[0]:=-maxint;
A[n+1]:=maxint;
end;
Procedure XuLi;
var i,j:integer;
begin
For i:=n downto 0 do
For j:=i+1 to n+1 do
if (a[i]begin
D[i]:=D[j]+1;
Tr[i]:=j;
end;
end;
Procedure GhiKq;
var v,max,t:integer;
begin

Assign(g,outfile);
Rewrite(g);
max:=D[0]-1;
Writeln(g,max);
v:=Tr[0];
While v<>n+1 do
begin
Writeln(g,a[v]);
v:=Tr[v];
end;
Close(g);
end;
Begin
Clrscr;
DocDl;
ChuanBi;
XuLi;
Ghikq;
End.

Bài 2 : Xếp va ly(A)
Một va ly có thể chứa W đơn vị trọng lợng.có n đồ vật mỗi vật có trọng lợng A[i] và có giá trị C[i]
hỏi lên chọn mỗi loại đồ vật bao nhiêu đẻ xếp vào valy sao cho tổng giá trị của valy là lớn nhất
6


Dữ liệu vào file valy.inp dong đầu tiên là số N và W, dòng thứ i trong số N dòng tiếp theo mỗi
dòng ghi hai số A[i] và C[i]
Kết quả ra : file valy.out theo quy cách sau
dòng đầu tiên là tổng giá trị lớn nhất tìm đợc của valy

các dòng tiếp theo mỗi dòng ghi hai số i (là số hiệu vật đợc chọn) x (là số lợng chọn vật i)
Ví dụ
valy.inp
valy.out
4 10
108
5 4
2 2
1 9
3 1
8 90
2 16
hớng dẫn : dùng mảng một chiều gọi D[i] là tổng giá trị lớn nhất khi thể tích là i, nh vậy
D[i]=Max(D[i-A[j]] + C[j]) với mọi 1<=j<=n 1<=i<=W
kết quả là giá trị lớn nhất trong mảng D ta xây dựng một mảng chọn với Chon[i] 1<=i<=W là giá trị tối u
trong phơng án chọn ở i và vật đợc chọn cuối cùng là Chon[i] Chơng Trình nh sau:
uses crt;
const
infile
outfile
maxn
maxW

= 'valy.inp';
= 'valy.out';
= 100;
= 5000;

Type


m1
m2
m3

= array [1..maxN] of integer;
= array [0..maxW] of longint;
= array [0..maxW] of integer;

Var

A,C,Sl
: m1;
D
: m2;
Chon
: m3;
N,W
: Integer;
Max
: Longint;
f,g
: Text;

Procedure NhapDl;
var i:integer;
begin
Assign(f,infile);
Reset(f);
Readln(f,N,W);
for i:=1 to n do

Readln(f,A[i],C[i]);
Close(f);
end;
Procedure ChuanBi;
begin
fillchar(D,sizeof(D),0);
fillchar(Chon,sizeof(Chon),0);
end;
Procedure XuLi;
var i,j:integer;
begin
for i:=1 to W do
for j:=1 to n do
if i>=A[j] then
if D[i]begin
D[i]:=D[i-A[j]]+C[j];

7


end;

Chon[i]:=j;
end;

Procedure XuLiKetThuc;
var i,j,u,v:integer;
begin
Max:=0;

for i:=1 to W do
if maxbegin
v:=i;
max:=D[i];
end;
fillchar(Sl,sizeof(Sl),0);
While Chon[v]<>0 do
begin
inc(Sl[Chon[v]]);
V:=V-A[Chon[v]];
end;
end;
Procedure GhiKQ;
var i:integer;
begin
Assign(g,outfile);
Rewrite(g);
Writeln(g,Max);
for i:=1 to n do
if Sl[i]<>0 then
Writeln(g,i,' ',Sl[i]);
Close(g);
end;
Begin
Clrscr;
NhapDl;
ChuanBi;
XuLi;
XuLiKetThuc;

GhiKq;
End.

Bài3 : xếp valy (B)
Cho n đồ vật mỗi đồ vật có trọng lợng A[i] và giá trị C[i] số lợng mỗi loại là một. Yêu cầu hãy xếp vào một
valy trọng lợng không quá W sao cho tổng giá trị lớn nhất

Dữ liệu vào file valy.inp dong đầu tiên là số N và W, dòng thứ i trong số N dòng tiếp theo mỗi
dòng ghi hai số A[i] và C[i]
Kết quả ra : file valy.out theo quy cách sau
dòng đầu tiên là tổng giá trị lớn nhất tìm đợc của valy
các dòng sau mỗi dòng ghi một số là số hiệu của vật đợc chọn.
Hớng dẫn : * tổ chức dữ liệu : Mảng hai chiều L(N,W) : L[i,j] là giá trị tối u của valy khi trọng lợng max là j
và xét các vật từ 1-->i
* khởi trị : L[0,j]=0 với mọi 0<=j <=W L[i,0]=0 với mọi 0<=i<=N
8


* X©y dùng L theo c«ng thøc :
L[i,j] = Max (L[i-1,j-a[i]]+ C[i],L[i-1,j]) nÕu A[i]<=j
hoÆc L[i,j] = L[i-1,j] nÕu A[i]>J

Ch¬ng Tr×nh :
{$A+,B+,D+,E+,F+,G+,I+,L+,N+,O+,P+,Q+,R+,S+,T+,V+,X+}
{$M 16384,0,655360}
uses crt;
Const infile = 'valy.inp';
outfile = 'valy.out';
MaxN
= 100;

MaxW
= 500;
Type

M1
= array [0..maxW] of Word;
M2
= array [0..maxN] of ^M1;
M3
= array [1..maxn] of integer;

Var

L
: M2;
A,C
: M1;
N,W
: integer;
f,g
: Text;

Procedure NhapDl;
var i:integer;
begin
Assign(f,infile);
Reset(f);
Readln(f,N,W);
for i:=1 to n do
Readln(f,A[i],C[i]);

Close(f);
end;
procedure ChuanBi;
var i,j:integer;
begin
for i:=0 to n do
begin
new(L[i]);
for j:=0 to w do
L[i]^[j]:=0;
end;
end;
function max(x,y:word):word;
begin
max:=x;
if xend;
procedure XuLi;
var i,j:integer;
begin
for i:=1 to n do
for j:=1 to w do
begin
if a[i]<=j then
L[i]^[j]:=Max(L[i-1]^[j-A[i]]+C[i],L[i]^[j])
Else L[i]^[j]:=L[i-1]^[j];
end;

9



end;
procedure GhiKq;
var i,j,max,v:integer;
begin
Assign(g,outfile);
Rewrite(g);
max:=0;
for i:=1 to w do
if maxbegin
max:=L[n]^[i];
v:=i;
end;
Writeln(g,max);
for i:=n downto 1 do
if L[i]^[v]<>L[i-1]^[v] then
begin
Writeln(g,i,' ',a[i],' ',c[i]);
v:=v-a[i];
end;
Close(g);
end;
Begin
Clrscr;
NhapDl;
Chuanbi;
XuLi;
GhiKq;
End.


Bài 4 : Bài toán chia kẹo
Cho n gói kẹo gói thứ i có A[i] cái kẹo.Yêu cầu hãy tìm cách chia các gói kẹo này thành hai phần
sao cho độ chênh lệch giữa tổng số kẹo ở hai phần là nhỏ nhất có thể.
Dữ liệu vào : file chiakeo.inp dòng đầu là số n
dòng thứ i trong số n dòng tiếp theo mỗi dòng ghi số A[i] là số kẹo có trong gói thứ i
(n<=100 và A[i]<=200)
kết quả : file chiakeo.out dòng đầu tiên là độ chênh lệch min
các dong sau ghi ra số hiệu các gói kẹo của một phần trong cách chia tìm đợc.
Hớng dẫn : để tìm cách chia các gói kẹo thành hai phần chênh lệch min thì cần chia sao cho tổng
số kẹo trong một phần gần với giá trị (Tong div 2) nhất, trong đó tong là tổng số kẹo của tất cả n
gói. Phơng án quy hoạch của ta ở đây là tìm ra một số các gói kẹo sao cho tổng số kẹo của nó gần
(tong div 2) nhất . Để làm đợc vậy ta dùng một mảng D là mảng một chiều và ta quy hoạch trên
mảng ấy với quy ớc D[i]=0 thì không có phơng án chọn ra trong số n gói kẹo một số gói để tổng số
kẹo trong các gói đợc chọn là i
còn D[i]<>0 thì có phơng án chọn ra một số gói kẹo sao cho tổng số kẹo các gói đợc chọn là i và
gói cuối cùng đợc chọn là D[i] nh vậy ta cần tìm một giá trị D[i]<>0 sao cho i lớn nhất và không vợt quá (tong div 2) .
Để làm đợc vậy ban đầu ta chuẩn bị một mảng D array[0..Tong div 2]
10


ở đây n<=100 a[i]<=200 nên Tong<=20000 vậy kích thớc tối đa của mảng D là 10000 ban đầu ta
cho D[0] nhận một giá trị khác 0 vì ban đầu ta khởi tạo cha chọn gói kẹo nào, các giá trị còn lại của
mảng D ta gán giá trị 0.
ta lần lợt xét từng gói kẹo từ 1 --> n giả sử khi xét đến gói thứ i ta sẽ tìm xem nếu có thêm gói kẹo
thứ i thì nó có thể thành lập đợc thêm những tổng nào cha đợc thành lập khi xét đến gói kẹo thứ i-1
và cứ nh vậy khi xét đến gói thứ n thì ta có đợc tất cả các cách chia khác nhau. Ta làm nh sau
Fillchar(D,sizeof(D),0);
D[0]:=1;
For i:=1 to n do

For j:=Tong Div 2 downto A[i] do
If (D[j]=0) and (D[j-A[i]]<>0 ) then
D[j-A[i]]:=i;
ta gán D[j-A[i]]:=i là để thuận tiện cho việc truy xuất kết quả.

Chơng trình nh sau :
Uses crt;
Const
infile
= 'Chiakeo.inp';
outfile
= 'Chiakeo.out';
maxn
= 100;
maxT
= 10000;
Type

m1
m2

= array [1..maxn] of byte;
= array [0..maxT] of byte;

Var

a
: m1;
d
: m2;

n,clmin,dich,Tong : integer;
f,g
: Text;

procedure docdl;
var i,j:integer;
begin
assign(f,infile);
reset(f);
readln(f,n);
for i:=1 to n do
readln(f,a[i]);
close(f);
end;
procedure chuanbi;
var i,j:integer;
begin
fillchar(d,sizeof(d),0);
d[0]:=1;
tong:=0;
for i:=1 to n do
tong:=tong+a[i];
dich:=tong div 2;
end;

11


procedure qhoach;
var i,j:integer;

begin
for i:=n downto 1 do
for j:=dich downto a[i] do
if (d[j]=0) and (d[j-a[i]]<>0) then
d[j]:=i;
end;
procedure ghikq;
var i,j:integer;
begin
while (dich>0) and (d[dich]=0) do Dec(dich);
Clmin:=abs(Tong-2*dich);
assign(g,outfile);
rewrite(g);
writeln(g,Clmin);
While dich>0 do
begin
Writeln(g,d[dich]);
dich:=dich-a[d[dich]];
end;
close(g);
end;

Begin
Clrscr;
docdl;
chuanbi;
qhoach;
ghikq;
End.


Bài 5 : di chuyển từ tây sang đông
Cho ma trận M*N mỗi ô chứa một số nguyên ta cần di chuyển từ một ô bất kì thuộc cột bên trái
sang một ô bất kì thuộc cột bên phải. Mỗi bớc di chuyển từ một ô (i,j) ta có thể đi sang ô (i-1,j+1)
hoặc (i,j+1) hoặc (i+1,j+1). Chi phí cho một đờng đi là tổng của các số nguyên trên con đờng đó.
Yêu cầu hãy tìm ra một con đờng đi với chi phí thấp nhất.
Dữ liệu vào : file Taydong.inp dòng đầu là số m , n
dòng thứ i trong số m dòng tiếp theo chứa n số nguyên trong phạm vi (-1000...1000) (m,n<=100)
Kết quả ra : file Taydong.out dòng đầu ghi một nguyên là chi phí min tìm đợc.
n dòng tiếp theo ghi chỉ số của hàng lần lợt di chuyển từ tây sang đông.
Ví dụ:
taydong.inp

taydong.out

44
2431
8529
1746

9
1
1
2

1 7 8 9

1

12



Hớng dẫn : theo cách di chuyển nh vậy ta nhận thấy tới ô (i,j) có thể đi từ ô (i-1,j-1) (i,j-1) (i+1,j-1)
và nh vậy ta quy hoạch nh sau.
Dùng C là bảng 2 chiều M*N và C[i,j] là chi phí min để di chuyển từ cột trái tới ô (i,j) nh vậy chi
phí min để di chuyển từ tây-->đông là giá trị nhỏ nhất của cột thứ n trong mảng C
C[i,j]:=Min(C[i-1,j-1],C[i,j-1],C[i+1,j-1]) + A[i,j];
CPMin=Min(C[i,n])

( 1<=i<=m)

Chơng trình dới đây dựa theo t tởng nh vậy nhng làm ngợc lại tức là quy hoạch từ đông sang tây để
tiện cho việc ghi kết quả và ta không khai báo thêm mảng C. Mảng C nói ở trên chỉ để lời hớng dẫn
đợc sáng sủa còn trong chơng trình ta có thể quy hoạch ngay trên mảng dữ liệu :
uses crt;
const infile
outfile
maxmn
maxc
Type
var

m1

= 'taydong.inp';
= 'taydong.out';
= 100;
= 1001;
= array [0..maxmn+1,1..maxmn] of integer;

a

: m1;
m,n,CPMin
: integer;
f,g
: text;

procedure DocDl;
var i,j:integer;
begin
Assign(f,infile);
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;
procedure ChuanBi;
var i,j:integer;
begin
for j:=1 to n do
begin
a[0,j]:=maxc;
a[m+1,j]:=maxc;
end;
end;
function Min(x,y,z:Integer):integer;

begin
if x>y then x:=y;
if x>z then x:=z;
Min:=x;
end;
procedure XuLi;
var i,j:integer;
begin
for j:=n-1 downto 1 do
for i:=1 to m do

13


A[i,j]:=Min(a[i-1,j+1],a[i,j+1],a[i+1,j+1])+A[i,j];
end;
procedure GhiKq;
var i,j,u,v,T:integer;
begin
Assign(g,outfile);
Rewrite(g);
CPMin:=A[1,1];i:=1;
for u:=2 to m do
if CPMin>A[u,1] then
begin
CPMin:=A[u,1];
i:=u;
end;
Writeln(g,CPMin);
for j:=1 to n-1 do

begin
Writeln(g,i);
T:= Min(a[i-1,j+1],a[i,j+1],a[i+1,j+1]);
if T = a[i-1,j+1] then Dec(i)
else if T = a[i+1,j+1] then Inc(i)
end;
Writeln(g,i);
Close(g);
end;
Begin
Clrscr;
DocDl;
ChuanBi;
XuLi;
GhiKq;
End.

Bài 6 : Rút bài ( cách diễn đạt khác của bài nhân ma trận)
Cho n lá bài xếp trên bàn và đánh số từ 1 tới n mỗi lá mang một số nguyên dơng theo đúng thứ tự đã
xếp là a1,a2,...,an . Mỗi lần ta đợc phép rút một lá bài ra khỏi dãy bài đang xếp và chi phí để rút lá bài
thứ i trong dãy là tích của ba số nguyên là ba số nghi trên lá bài rút ra và hai lá bài đặt cạnh nó ở thời
điểm hiện tại.
(lu ý : với cách tính chi phí nh vậy thì ta không rút hai lá bài ở hai đầu. Mỗi lần rút thì tập bài sẽ thu
hẹp lại một lá và nh vậy có sự thay đổi về vị trí bên cạnh của hai lá bài cạnh lá vừa rút)
Yêu cầu : hãy rút đi n-2 lá bài với chi phí nhỏ nhất. Bạn hãy tìm và in ra cách rút đó
Dữ liệu vào : file card.inp dòng đầu tiên là số n dòng thứ i trong n dòng tiếp theo mỗi dòng ghi số
nguyên ai (n<=100 ai<=100)
Kết quả ra : file card.out dòng đầu tiên ghi chi phí min để rút n-2 lá bài dòng thứ i trong số n-2 dòng
tiếp theo bài ghi chỉ số của lá bài đợc rút theo số hiệu ban đầu.
Hớng dẫn : dùng mảng hai chiều C[i,j] có ý nghĩa là chi phí tối thiểu để rút hết các lá bài thuộc đoạn

[i,j] theo thứ tự ban đầu, nh vậy C[i,j] đợc tính từ các giá trị C[i,k-1] và C[k+1,j]
( i=C[i,j]=Min(C[i,k-1]+C[k+1,j]+Chiphí(Rút lá bài k khi đã rút hết các đoạn [i,k-1] và [k+1,j]))
k đợc hiểu là lá bài cuối cùng đợc rút trong đoạn [i,j] trong phép rút tối u

14


PhÇn 3 : mét sè bµi luyÖn quy ho¹ch ®éng
15


Bài toán 1 :ngân hàng trả tiền
Một người đi lấy tiền ở một ngân hàng. Anh ta cần lấy một khoản đúng M đồng. Ngân hàng có N
đồng tiền A1, A2,.., AN. Hỏi ngân hàng có bao nhiêu cách trả tiền.
Dữ liệu vào trong file: "MONEY.INP" có dạng:
+ Dòng đầu là hai số N và M (N <=100, M <= 10000)
+ Các dòng tiếp theo là các phần tử của mảng A.
Kết quả ra file: "MONEY.OUT" gồm một dòng duy nhất là số cách trả tiền (Số cách trả tiền <
Maxlongint)
vi du :
MONEY.INP

MONEY.OUT

5 10

3

12345


Bài toán 2 : Dãy có tổng chia hết cho k (đề thi toàn Quốc)
Cho một dãy số nguyên A1, A2,.., AN và một số k. Hãy tìm một dãy con (không nhất thiết phải liên
tiếp nhau) dài nhất có tổng các số chia hết cho số k.
Dữ liệu vào trong file "dayso.inp" có dạng:
+ Dòng 1 gồm 2 số N và k (N<=1000; k<=50)
+ Các dòng tiếp theo chứa các số của mảng A.
Kết quả ra file "dayso.out" gồm một dòng ghi số phần tử lớn nhất tìm được.

DAYSO.INP

DAYSO.OUT

65

5

127345
Bài toán 3 : mua bán hàng
Có một người đi mua hàng, anh ta có N đồng tiền d1, d2,.., dN. Người bán hàng có M đồng tiền b1,
b2,.., bm. Anh ta muốn mua một mặt hàng với giá trị W. Hỏi cuộc mua bán có thể diễn ra được
không?
Giới hạn: M, N<=100 và di, bj <=100.
Bài toán 4 : xoay DOMINO
Cho N thanh DOMINO xếp theo chiều dọc như hình vẽ.
Ví dụ hình trên gồm 5 thanh DOMINO.
16


Mỗi thanh DOMINO gồm 2 phần, phần trên và phần dưới. Trên mỗi phần có một số từ 1 đến 6.

Yêu cầu đặt ra là hãy tìm cách xoay các thanh (xoay 180 độ) để sau khi xoay chênh lệch giữa tổng
trên và tổng dưới là ít nhất.
Giới hạn: N<=1000.
Bài toán 5 : Giá trị biểu thức
Giả thiết X,Y là hai số nguyên dương. Kí hiệu Sx là tổng các chữ số trong dạng biểu diễn cơ số 10
của X, Dmax_y là chữ số lớn nhất và Dmin_y là chữ số nhỏ nhất trong dạng biểu diễn cơ số 10 của
Y. Phép tính hai ngôi # với các toán hạng nguyên dương X,Y được định nghĩa như sau:
( X#Y ) = Sx*Dmax_y + Dmin_y
Ví dụ:
(30#9) = 3*9 + 9 = 36
(9#30) = 9*3 + 0 = 27
Với X cho trước, một số biểu thức hợp lệ là:
(X#X)
((X#X)#X)
(X#(X#X)#(X#X)#X)
Ký hiệu kết quả biểu thức là K. Cho X và K (0 < X,K < 109-1) cần xác định số ít nhất m các phép #
để từ đó có thể xây dựng biểu thức thuộc dạng đang xét với X cho kết quả K và biểu diễn của biểu
thức.
Dữ liệu vào từ file văn bản BT.IN, dòng thứ nhất chứa X, dòng thứ hai chứa K.
Kết quả ra file văn bản BT.OUT, dòng thứ nhất chứa m, dòng thứ hai chứa biểu thức.
Ví dụ:
BT.IN

BT.OUT

718

3

81


((718 #(718 #718)) #718)

Bài toán 6 : Lịch thuê nhân công
Có một dự án kéo dài trong T tháng và người quản lý cần phải lập lịch sử dụng công nhân trong dự
án, anh ta biết số công nhân tối thiểu cần trong mỗi tháng. Mỗi khi thuê hay sa thải một công nhân
thì đều phải mất một chi phí xác định, mỗi công nhân được thuê sẽ vẫn nhận được lương tháng
ngay cả khi không sử dụng anh ta làm việc.
Với mỗi công nhân, người quản lý biết chi phí thuê, chi phí sa thải và tiền lương phải trả cho công
nhân đó trong 1 tháng. Và bài toán đặt ra như sau: Cần phải thuê hay sa thải bao nhiêu công nhân
mỗi tháng để tổng chi phí dành cho nhân công của dự án là nhỏ nhất, tức là giảm tối đa chi phí của
dự án.
17


Dữ liệu vào từ file văn bản EMPLOY.IN có cấu trúc như sau:
- Dòng đầu ghi T là số tháng diễn ra dự án (T=<100).
- Dòng thứ hai ghi 3 số lần lượt là chi phí thuê, lương tháng, chi phí sa thải mỗi công nhân.
- Dòng cuối cùng là T số nguyên dương, số thứ i cho biết số công nhân tối thiểu cần cho tháng thứ
i, các giá trị số không quá 150.
Kết quả ra file văn bản EMPLOY.OUT theo định dạng:
- Dòng thứ nhất ghi tổng chi phí nhỏ nhất tìm được.
- Dòng thứ hai ghi T số, số thứ i là số công nhân hoạt động trong dự án tại tháng thứ i.
Ví dụ về file dữ liệu vào và file kết quả ra:
EMPLOY.IN

EMPLOY.OUT

3


265

456

10 10 11

10 9 11
***
Đề bài này hơi rắc rối khó hiểu một chút vì vậy cần phải đọc kỹ, nắm chắc. Rõ ràng việc thuê thêm
hay sa thải công nhân đều phải chịu phí tổn nên thấy: để đảm bảo chi phí ít nhất cho việc thuê nhân
công trong cả dự án thì số công nhân đang thuê trong một tháng không nhất thiết phải là số công
nhân tối thiểu cần cho tháng đấy. Ví dụ, phí tổn để thuê cũng như sa thải công nhân rất lớn thì
không dại gì ta lại thường xuyên thuê rồi lại sa thải người trong từng tháng, tốt nhất nên giữ họ và
trả lương (dù họ không làm gì). Nhiệm vụ của chúng ta trong mỗi tháng phải quyết định có bao
nhiêu công nhân trong biên chế thuê, nghĩa là phải quyết định xem cần thuê hay cần sa thải bao
nhiêu công nhân trong biên chế của tháng trước. Nếu gọi T_max là số công nhân của tháng cần
nhiều người nhất thì rõ ràng số công nhân trong biên chế thuê của một tháng bất kỳ trong dự án
không bao giờ vượt quá T_max. Xét một tháng nào đó, biết rằng không nên sử dụng quá T_max
người và cũng không được phép sử dụng ít hơn số người tối thiểu cần cho tháng đấy, nhưng phải
chọn giá trị nào trong khoảng giới hạn này? Đến đây nếu các giá trị của T và T_max là nhỏ thì có
thể duyệt tìm ra kết quả tối ưu nhưng do các giá trị này lại có thể khá lớn nên buộc phải tìm cách
khác hiệu quả hơn.
Bài toán 7 :Tiền kim loại
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 là 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ả 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.
Ví dụ 1: Cho thông tin về N=8 đồng tiền như sau:
i
vi
wi
18


1
1
1
2
2
1
3
4
1
4
8
1
5
16
1
6
32
1
7
64
1
8

128 1
với V=141 và W=4 ta có số đồng lớn nhất M=4 vì 4 đồng lần lượt thuộc 4 loại 1, 3, 4, 8 có tổng giá
trị là 141 và tổng trọng lượng 4.
Ví dụ 2: Cho thông tin về N=4 đồng tiền như sau:
i
vi
wi
1
12 3
2
4
7
3
8
10
4
21 19
với V=11 và W=17 thì M=0 vì không có cách chọn các đồng thoả mãn hai giá trị V và W.
Dữ liệu vào từ file COIN.IN có cấu trúc:
- Dòng đầu 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ả ghi ra file COIN.OUT giá trị M thoả mãn yêu cầu đặt ra, ghi M=0 nếu không tìm được
cách thoả mãn.
trọng lượng là W, và trong M đồng này có một đồng loại i, thế thì với tổng giá trị V-vi, tổng Ví dụ
về file dữ liệu vào và file kết quả ra:
COIN.IN
COIN.OUT
COIN.IN COIN.OUT
8 141 4

4
4 11 17
0
11
12 3
21
47
41
8 10
81
21 9
16 1
32 1
64 1
128 1
Bài toán này không phải là một bài khó và dễ dàng hơn nếu ta đánh giá rằng: giả sử có trong tay số
ít nhất M đồng tiền để tổng giá trị là V, tổng trọng lượng W-wi chắc chắn cần số ít nhất là M-1
đồng tiền, i=1..N. Nhận xét này cho thấy công thức truy hồi nếu muốn tính M. Xét mảng
Coin[1..150,1..150], Coin[i,j] cho biết số tối thiểu đồng tiền thỏa mãn điều kiện số đồng tiền này có
tổng giá trị là i, tổng trọng lượng là j, (i=1..V, j=1..W) thế thì:
Coin[i,j] = Min{Coin[i-v[k], j-w[k]] +1}

Bài toán 8 : Xoay ô
Cho một lưới ô vuông kích thước M´N (M<= 50, N<= 8). Mỗi ô vuông được chia thành 4 miền
bằng hai đường chéo, mỗi miền được tô đen hoặc trắng. Với bất cứ một ô nào, có thể lấy giao điểm
hai đường chéo của ô đó làm tâm và xoay ô đó đi một góc 900, 1800 hoặc 2700.
19


T mt bng ban u, ngi ta mun xoay cỏc ụ sao cho hai min chung cnh phi cú cựng mu.

Tt nhiờn l cú nhiu cỏch xoay cỏc ụ t c mong mun nhng yờu cu t ra l tỡm mt
cỏch xoay cỏc ụ sao cho tng s ụ phi thc hin phộp xoay l nh nht cú th c
D liu vo t file vn bn XOAY.IN bao gm:
- Dũng u l hai s M v N
- M dũng tip theo, dũng th i gm N b 4 s (xij 1,xij2,xij3,xij4) th hin tỡnh trng cỏc min ti ụ
(i,j) trờn bng vi qui c:
1: min tụ en
0: min tụ trng
V:
xij1: min trờn
xij2: min trỏi
xij3: min di
xij4: min phi
Kt qu ra file XOAY.OUT th hin:
- Nu khụng cú cỏch xoay thỡ ghi s 0.
- Nu tn ti nghim thỡ dũng u tiờn ghi tng s phộp xoay, tip theo l M dũng, mi dũng N b
s cho bit tỡnh trng ca bng sau khi thc hin cỏc phộp xoay.
Vớ d v file d liu vo v file kt qu ra:
XOAY.IN
XOAY.OUT
22
2
10001010
10001010
00010001
01001000
Bài toán 9 : cho dãy n phần tử nguyên a1,a2...an. Một phép rút gọn dãy làm cho dãy giảm đi một
phần tử, phép rút gọn dãy tại vị trí thứ i nh sau : + gán a(i) cho a(i)-a(i+1)
+ loại bỏ a(i+1) ra khỏi dãy
+ đẩy đoạn (i+2) đến (n) thành đoạn (i+1)

đến (n-1). Nh vậy sau mỗi phép rút gọn dãy giảm đi một phần tử.
Yêu cầu : hãy tìm ra thứ tự rút gọn sao cho sau n-1 phép rút gọn dãy còn lại một phần tử và nó nhận
giá trị T
Dữ liệu vào : file RG.inp dòng đầu là n và T
dòng thứ i trong số n dòng tiếp theo ghi số ai
Kết quả ra : file RG.out dòng đầu là 0 hoặc 1 thể hiện có hay không phơng án rút gọn để đạt kq T.
Nếu dòng đầu là 1 thì n-1 dòng tiếp theo ghi mỗi dòng một phép rút gọn theo đúng thứ tự đã thực
hiện để đạt đợc kết quả T.
Bi toỏn 10: Palindrome (time limit 2s)
Mt xõu c gi l xõu i gng nu c t trỏi qua phi cng ging nh c t phi qua trỏi. Vớ
d xõu "madam" l mt xõu i gng. Bi toỏn t ra l cho mt xõu S gm cỏc kớ t thuc tp
M=[a..z], hóy tỡm cỏch chốn vo xõu S cỏc kớ t thuc tp M ti cỏc v trớ bt kỡ vi s lng kớ
t chốn vo l ớt nht xõu S thnh xõu i gng. Vớ d: xõu: "adbhbca" ta s chốn thờm 2 kớ t (
c v d) c xõu i gng "adcbhbcda".
D liu vo trong file PALIN.IN cú dng:
Dũng th nht l mt s nguyờn dng T (T <=10) l s b test
T dũng sau, mi dũng cha mt xõu S, di mi xõu khụng vt quỏ 500.
Kt qu ghi ra file PALIN.OUT cú dng: Gm nhiu dũng, mi dũng l mt xõu i gng sau khi
ó chốn thờm ớt kớ t nht vo xõu S tng ng file input.
palin.inp

palin.out

1

Abcba
20


abca

Bài toán 11: Có N người sắp hàng mua vé dự buổi hoà nhạc. Ta đánh số họ từ 1 đến n theo thứ tự
đứng trong hàng. Mỗi người cần mua một vé, song người bán vé được phép bán cho mỗi người tối
đa 2 vé. Vì thế một số người có thể rời hàng và nhờ người đứng trước mình mua hộ vé. Biết t i là
thời gian cần thiết để người i mua xong vé cho mình. Nếu người i+1 rời khỏi hàng và nhờ người i
mua hộ vé thì thời gian để người thứ i mua được vé cho cả hai người là ri.
Yêu cầu: Xác định xem những người nào cần rời khỏi hàng và nhờ người đứng trước mua vé để
tổng thời gian phục vụ bán vé là nhỏ nhất.
Dữ liệu: Vào từ file TICK.INP.
- Dòng đầu tiên chứa số n (1- Dòng thứ 2 ghi N số nguyên dương t1, t2,.. ,tn.
- Dòng thứ 3 ghi N-1 số nguyên dương r1, r2,.. ,rn-1.
Kết quả: Ghi ra file văn bản TICK.OUT.
- Dòng đầu tiên ghi tổng số thời gian phục vụ.
- Dòng tiếp theo ghi chỉ số của các khách hàng cần rời khỏi hàng (nếu không có ai cần rời khỏi
hàng thì quy ước ghi một số 0).
Ví dụ :
tick.inp
tick.out
5
18
25784
24
4 9 10 10
Bài toán 12
Ba bạn Kiên, Hùng, Thành chơi rất thân với nhau, bạn Hùng học chuyên Toán còn hai bạn Thành
và Kiên học lớp chuyên Tin. Một lần, bạn Hùng mang ra N khối đá ( N ≤ 5000 ), các khối đá đều
có dạng hình hộp chữ nhật và được đặc trưng bởi 3 kích thước. Một cách xây tháp là cách đặt một
số khối đá trong các khối đã cho chồng lên nhau theo quy tắc:
- Chiều cao của mỗi khối đá là kích thước nhỏ nhất trong 3 kích thước.
- Các mép của các khối được đặt song song với nhau sao cho không có phần nào của khối trên nằm

chìa ra ngoài khối dưới.
Trong lúc các bạn còn đang ngạc nhiên, Hùng nói:
'Bây giờ, từ N khối đá này, Thành hãy giúp tớ xây được một cái tháp để số các khối đá còn lại sau
khi xây là ít nhất. Còn Kiên, cậu chờ Thành làm xong rồi xây cho tớ cái tháp có chiều cao lớn nhất
cũng từ N khối đá này nhé! Được không!'
Thành và Kiên cười : 'Chuyện nhỏ! Cái món này thì đúng sở trường của dân Tin bọn anh rồi chú
em ạ!. Hùng khoanh tay: 'Thì cứ thử xem !. Và ngay lập tức, Kiên và Thành bắt tay vào làm.
Còn bạn, bạn còn chờ gì nữa mà không thử sức với bài toán tin này.
Dữ liệu vào: Hung.inp ghi thông tin về các khối đá mà Hùng đem ra:
- Dòng đầu là số N.
- N dòng sau, dòng thứ i ghi 3 số nguyên dương không quá 255 là kích thước của khối đá thứ i.
Dữ liệu ra: Kien.out ghi cách xếp tương ứng với câu Hùng hỏi Kiên:
- Dòng đầu là số khối đá của tháp
- Các dòng sau mỗi dòng ghi các khối đá theo thứ tự từ đáy tháp lên đỉnh tháp, mỗi dòng một số
theo thứ tự là: T, D, R, C, trong đó T là số hiệu khối đá, D là chiều dài, R là chiều rộng và C là
chiều cao của khối đá tương ứng.
Thanh.out ghi cách xếp tương ứng với câu Hùng hỏi Thành theo quy cách giống như trên.
21


Với mọi bộ dữ liệu thoả mãn, chương trình của bạn không được chạy quá 5 giây và nếu dưới 3 giây
thì càng tuyệt vời (đặt {$R-}).
Ví dụ:
hung.inp
kien.out
thanhout
12
4
5
755

1755
8921
448
11 5 5 5
6611
115
5553
10 6 1 1
422
4422
3511
535
12 5 1 1
611
427
291
133
116
555
511
Bài toán 13: Một đại lý kinh doanh xăng dầu có n trạm bán xăng dầu (gọi tắt là cây xăng) đánh số
từ 1 đến n trên một đường cao tốc muốn tìm vị trí đặt k bể chứa xăng để cung ứng xăng cho các cây
xăng. Trên đường cao tốc người ta đặt các cột mốc cây số, bắt đầu từ cột số 0. Biết vị trí của cây
xăng thứ i là ở cột cây số di (i=1,2,...,n): d1 < d2 < ...n
Yêu cầu: Tìm vị trí đặt k bể chứa xăng tại k trong số n cây xăng sao cho khoảng cách lớn nhất từ
cây xăng không có bể chứa đến cây xăng có bể chứa gần nó nhất là nhỏ nhất.
Dữ liệu: Vào từ file văn bản VITRI.INP
- Dòng đầu tiên ghi 2 số nguyên dương n, k (n<200, k<30,k
- Dòng thứ 2 ghi các số d1, d2,...,dn (di là các số nguyên dương không quá 320000). Các số trên cùng
một dòng ghi cách nhau ít nhất một dấu trắng.

Kết quả: Ghi ra file văn bản VITRI.OUT
File gồm k dòng, mỗi dòng ghi chỉ số cây xăng đặt bể chứa xăng
Ví dụ:
vitri.inp

vitri.out

63

2

5 6 12 19 20
27

4
6

Bài toán 14
Cho n bức tranh mã số từ 1..n (n<=50). Người ta cần chọn ra một bức để đặt ở cửa phòng tranh, số
còn lại được treo thẳng hàng trong phòng trên m vị trí định sẵn có mã số 1..m từ trái qua phải. Các
bức tranh phải được treo theo trật tự nghiêm ngặt sau đây: tranh có số hiệu nhỏ phải treo ở trên
tranh có số hiệu lớn.
Biết các thông tin sau về mỗi bức tranh:
22


- Tranh thứ i treo tại cửa sẽ đạt trị thẩm mỹ c[i];
- Tranh thứ i treo tại vị trí j sẽ đạt trị thẩm mỹ v[i,j].
- m+1≥n.
- Các giá trị thẩm mỹ là những số tự nhiên không vượt quá 50.

Yêu cầu: Hãy xác định một phương án treo tranh để có tổng trị thẩm mỹ là lớn nhất.
Dữ liệu vào: Tệp văn bản 'Picture.INP'
- Dòng thứ nhất ghi n, m (cách nhau 1 dấu cách)
- Dòng tiếp theo là n giá trị c.
- Tiếp đến là n dòng, dòng i gồm m vị trí v[i,1], v[i,2],..v[i,m].
Dữ liệu ra: Tệp văn bản ' Picture.OUT'
- Dòng thứ nhất ghi giá trị thẩm mỹ lớn nhất tìm được
- Dòng thứ hai: ghi mã số hiệu bức tranh treo ở cửa phòng tranh.
- Dòng thứ 3 ghi n-1 số tự nhiên sắp tăng chặt cho biết mã số các vị trí được chọn để treo tranh
picture.inp

picture.out

34

40

1 20 1

2

1 10 1 3

24

2122
1 3 0 10
Bài toán 15 Có một số quân cờ nhảy, mỗi quân được sơn một trong số K màu khác nhau (K ≤ 25).
Trên mỗi quân cờ ghi một số nguyên không âm bằng một trong số N số nguyên không âm cho
trước (N ≤ 101). K quân cờ có màu khác nhau từng đôi một tạo thành một bộ cờ. Hai bộ cờ gọi là

giống nhau, nếu số ghi trên các quân cờ cùng màu là như nhau. Trong trường hợp ngược lại hai bộ
cờ gọi là khác nhau. Tổng các số ghi trên các quân của một bộ cờ gọi là trọng số của nó.
Yêu cầu: Hãy tìm số bộ cờ khác nhau có cùng trọng số S (0 < S ≤ 300).
Dữ liệu: Vào từ file văn bản COMPLETE.INP:
Dòng đầu tiên chứa số nguyên K,
Kết quả: Đưa ra file văn bản COMPLETE.OUT số lượng tìm được (nguyên).
Ví dụ
complete.inp
6
2
2
01

complete.out
15

Bài toán 16 Giám đốc một công ty trách nhiệm hữu hạn muốn xin chữ kí của ông kiến trúc sư
trưởng thành phố phê duyệt dự án xây dựng trụ sở làm việc của công ty. Ông kiến trúc sư trưởng
chỉ ký vào giấy phép khi bà thư ký của ông ta đã ký duyệt vào giấy phép. Bà thư kí làm việc tại
tầng thứ M của một toà nhà được đánh số từ 1 đến M, từ thấp lên cao. Mỗi tầng của toà nhà có N
phòng được đánh số từ 1 đến N, từ trái sang phải. Trong mỗi phòng chỉ có 1 nhân viên làm việc.
Giấy phép của bà thư kí ký duyệt khi có ít nhất một nhân viên ở mỗi tầng của toà nhà đã kí xác
23


nhận. Một nhân viên bất kỳ có thể chỉ kí xác nhận vào giấy phép khi có ít nhất một trong các điều
kiện sau được thoả mãn:
* Nhân viên đó làm việc ở tầng 1
* Giấy phép đã được kí xác nhận bởi một nhân viên làm việc ở phòng liền kề (hai phòng được gọi
là liền kề khi chỉ số phòng sai khác nhau một đơn vị)

* Giấy phép được kí xác nhận bởi nhân viên làm việc ở phòng cùng số phòng ở tầng dưới.
Mỗi nhân viên khi đã kí xác nhận đều phải có một chi phí nhất định. Hãy chỉ ra cách xin chữ kí sao
cho xin được chữ kí của ông kiến trúc sư trưởng mà chi phí bỏ ra là ít nhất.
Dữ liệu:
Vào từ file Sign.Inp như sau:
* Dòng đầu tiên ghi M, N (1 <= M <= 100; 1 <= N <= 500);
* Dòng thứ i trong số M dòng tiếp theo ghi N số biểu diễn chi phí phải trả khi kí ở các phòng của
tầng i. Các số cách nhau bởi một dấu cách.
Kết quả:
Ghi ra file: Sign.Out như sau:
* Dòng đầu tiên ghi hai số F, K theo thứ tự là chi phí cần trả và số lượng phòng cần đi qua.
* K dòng tiếp theo ghi thông tin của các phòng theo thứ tự cần đi qua, mỗi dòng ghi 2 số là số thứ
tự tầng và chỉ số phòng tương ứng.
Ví Dụ:
SIGN.INP
44
3225
7933
5 3 10 7
10 10 15 8

SIGN.OUT
23 5
13
23
24
34
44

Bài toán 17 Cho trước số tự nhiên N (1< N <100)

Xét tất cả các phân tích N thành tổng các số tự nhiên
N = a1 + a2 +... +ak (1)
Tìm giá trị lớn nhất của BSCNN (a1,a2,, ..., ak) trên tập các bộ số (a1,a2,..., ak) thoả mãn đẳng thức
(1).
Dữ liệu vào: từ file văn bản BSCNN.INP: là 1 số N
Kết quả: Ghi ra file văn bản BSCNN.OUT, bao gồm 2 dòng, dòng thứ nhất ghi giá trị số Max tìm
được. Dòng thứ hai ghi n bộ số a1,a2,, ..., ak tương ứng, các số cách nhau bằng dấu cách.
Ví dụ.
bscnn.inp

bscnn.out

22

420
33457
24


Bài toán 18
Một toà nhà gồm có N tầng đánh số từ 1 đến N (N≤100), và chỉ có một thang máy để phục vụ.
Trong một ngày, có tất cả M yêu cầu vận chuyển bằng thang máy (M≤100), mỗi yêu cầu được mô
tả bằng 2 số a, b cho biết cần vận chuyển hàng từ tầng a đến tầng b. Do yêu cầu vận chuyển nên
thang máy không thể phục vụ 2 yêu cầu cùng một lúc mà phải xong một yêu cầu mới đến yêu cầu
khác. Tuy nhiên người ta có thể thay đổi thứ tự thực hiện các yêu cầu. Bài toán đặt ra là tìm thứ tự
thực hiện các yêu cầu sao cho tổng quãng đường thang máy phải đi là ít nhất.
Thang máy ban đầu xuất phát từ tầng 1.
Input:
Cho trong file text Elevator.dat :
Dòng đầu là 2 số N, M.

M dòng tiếp theo, dòng thứ i ghi 2 số a, b mô tả yêu cầu thứ i.
Output:
File Elevator.out có cấu trúc:
Dòng đầu là tổng quãng đường tìm được.
Dòng thứ hai mô tả thứ tự thực hiện các yêu cầu bởi một hoán vị của 1, 2,..., M.
Ví dụ:
Elevator.inp

Elevator.out

53

9

15

132

34
52
Bài toán 19
Một trung tâm thương mại cao 150 tầng. Trên mỗi tầng đều có các ngân hàng chứa tiền. Toà nhà bị
bọn khủng bố tấn công bằng máy bay. Máy bay cảm tử của bọn khủng bố đâm vào tầng j của toà
nhà và gây ra cháy. Đám cháy này lan từ tầng k xuống với tốc độ 10 phút/tầng. Một tên cướp đang
ở tầng 1 thấy đây là một thời cơ để kiếm tiền vì lúc này mọi người đều lo thoát thân. Hắn ta sử
dụng 1 thang máy đặc biệt để đi lấy tiền. Thang máy này có tốc độ là 1phút/1 tầng. Nếu dừng lại để
lấy tiền ở mỗi tầng hắn mất 15 phút. Nhân chứng cho thấy rằng hắn có số liệu vể lượng tiền có ở
mỗi tầng. Sau khi đám cháy được dập tắt và người ta đang thống kê thiệt hại. Do tài liệu sổ sách về
số tiền có trước khi toà nhà bị khủng bố và một số lượng tiền đã bị cháy nên người ta không thể
biết được là tên cướp đã lấy được bao nhiêu tiền. Vì vậy cảnh sát đã nhờ một trung tâm Tin học

kiểm tra xem số tiền tối đa mà tên cướp có thể lấy được.
Dữ liệu vào: Đọc từ file WTC.INP
- Dòng thứ nhất chứa số K (0 < K <= 150) là tầng mà máy bay của tên khủng bố đã đâm vào.
- Dòng tiếp theo ghi các số t[2], t[3], … , t[k-1] tương ứng là số tiền có ở các tầng 2, 3,…, k-1
Kết quả: ghi ra file WTC.OUT gồm:
- Dòng đầu tiên ghi số tiền lớn nhất mà tên cướp đã có thể lấy.

25


×