Nguồn đề bài: http://vn.spoj.com/problems/COIN34/
1. Đề bài COIN34 spoj
Bạn có 34 đồng xu có giá trị như sau:
xu(1) có giá trị 2
xu(2) có giá trị 3
xu(3) có giá trị 5
for n = 4 to 34
xu(n) có giá trị (xu(n-1) + xu(n-2) + xu(n-3))
Bạn hãy dùng nhiều đồng xu nhất để mua một món hàng có giá là X!
Dữ liệu
Dòng đầu tiên là số test (không quá 1000). Mỗi dòng tiếp theo chứa một số nguyên X (1 ≤ X ≤ 2000000000).
Kết quả
Với mỗi test, in ra “Case #” + số hiệu test + “: ” + số lượng lớn nhất đồng xu cần dùng. Nếu không có cách nào để đạt giá trị X thì in ra -1.
Ví dụ
Dữ liệu 4 1 5 8 9 Kết quả Case #1: -1 Case #2: 2 Case #3: 2 Case #4: -1
2. Hướng dẫn COIN34 spoj 34 đồng xu
Thuật toán : Duyệt phân tập
Duyệt 2 phần : 1..20, và 21..34
3. Code tham khảo COIN34 spoj 34 đồng xu
* Đã bổ sung code của admin
Code của admin:
const fi='COIN34.inp';
nmax=10000;
maxx=367980;
type data=longint;
var
test,n:data;
f:text;
A:array[0..34] of data;
B:array[0..maxx] of byte;
res,x:data;
function max(a,b:byte):byte;
begin
if a>b then exit(a);
exit(b);
end;
procedure try1(i,s:data; slxu:byte);
begin
if i>20 then exit;
try1(i+1,s+a[i],slxu+1);
b[s+a[i]]:=max(b[s+a[i]],slxu+1);
try1(i+1,s,slxu);
end;
procedure try2(i,s:data; slxu:byte);
begin
if i>34 then exit;
try2(i+1,s+a[i],slxu+1);
if (x-(s+a[i])>=0) and (x-(s+a[i])<=maxx)then
begin
if ((x-(s+a[i])>=0) and (B[x-(s+a[i])]<>0)) or (x-(s+a[i])=0) then
res:=max(res,B[x-(s+a[i])]+slxu+1);
end;
try2(i+1,s,slxu);
end;
procedure docfile;
var i,j:data;
begin
A[1]:=2;
a[2]:=3;
a[3]:=5;
fillchar(b,sizeof(b),0);
for i:=4 to 34 do
A[i]:=a[i-1]+a[i-2]+a[i-3];
res:=0;
for i:=1 to 20 do
res:=res+a[i];
res:=0;
try1(1,0,0);
assign(f,fi); reset(f);
readln(f,test);
for i:=1 to test do
begin
res:=0;
readln(f,x);
if x<=maxx then
res:=B[x]
else
try2(21,0,0);
if res=0 then
res:=-1;
writeln('Case #',i,': ',res);
end;
close(f);
end;
begin
docfile;
end.
const
COIN = 34;
maxm = 391230;
var
n, res : byte;
test, i,
x : longint;
a, t : array[0..coin] of longint;
f : array[0..maxm] of byte;
count : array[0..coin] of byte;
procedure init;
var i : byte;
begin
a[1]:= 2; a[2]:= 3; a[3]:= 5;
for i:= 4 to 34 do
a[i]:= a[i-1] + a[i-2] + a[i-3];
end;
procedure duyet1(i : byte);
var j : byte;
begin
for j:= 0 to 1 do
begin
t[i]:= t[i-1]; count[i]:= count[i-1];
if j=1 then
begin
inc(t[i], a[i]); inc(count[i])
end;
if i < 20 then
duyet1(i+1)
else if count[i] > f[t[i]] then
f[t[i]]:= count[i]
end;
end;
function max(a, b : byte): byte;
begin
if a > b then
max:= a
else max:= b
end;
procedure duyet2(i : byte);
var j : byte;
begin
for j:= 0 to 1 do
begin
t[i]:= t[i-1]; count[i]:= count[i-1];
if j=1 then
begin
inc(t[i], a[i]); inc(count[i]);
end;
if i < coin then
duyet2(i+1)
else if (x - t[i] >= 0) and (x - t[i] <= maxm) then
if ((x - t[i] > 0) and (f[x - t[i]] <> 0))
or (x - t[i] = 0) then
res:= max(res, f[x-t[i]] + count[i])
end
end;
begin
init;
duyet1(1);
readln(test);
t[20]:= 0; count[20]:= 0;
for i:= 1 to test do
begin
readln(x);
res:= 0;
if x <= maxm then
res:= max(res, f[x]);
duyet2(21);
if res=0 then
writeln('Case #', i, ': -1')
else writeln('Case #', i, ': ', res)
end;
readln
end.