8 2 5
14
这道题目千万不要被题目现象的表面所迷惑,看起来很复杂,其实这道题目就是一道dfs题,一点也不难,唯一不同的是要加记忆化。
算法实现:
搜索每个优惠价买多少种,然后每次买个优惠价就更新sum。
记忆化——判断5种商品在分别买多少个时的sum要最小,不然就没必要继续递归了。
代码:
var
s,b,i,j,sum,ans:Longint;
c,w:array[1..99,1..5] of Longint;
num:array[1..5] of Longint;
tot,money:array[0..999] of Longint;
n,p:array[1..99] of Longint;
f:array[0..5,0..5,0..5,0..5,0..5] of longint;
procedure dfs(k,sum:longint);
var
i,j,min,t,x:longint;
begin
if sum<ans then ans:=sum;
if f[tot[num[1]],tot[num[2]],tot[num[3]],tot[num[4]],tot[num[5]]]>=sum then
f[tot[num[1]],tot[num[2]],tot[num[3]],tot[num[4]],tot[num[5]]]:=sum
else
exit;
if k>s then exit;
min:=maxLongint;
for x:=1 to n[k] do
if tot[c[k,x]] div w[k,x]<min then min:=tot[c[k,x]] div w[k,x];
for i:=0 to min do
begin
t:=0;
for j:=1 to n[k] do
begin
dec(tot[c[k,j]],w[k,j]*i);
inc(t,w[k,j]*money[c[k,j]]*i);
end;
dfs(k+1,sum-t+i*p[k]);
for j:=1 to n[k] do
inc(tot[c[k,j]],w[k,j]*i);
end;
end;
begin
readln(s);
for i:=1 to s do
begin
read(n[i]);
for j:=1 to n[i] do
read(c[i,j],w[i,j]);
readln(p[i]);
end;
readln(b);
for i:=1 to b do
begin
readln(num[i],tot[num[i]],money[num[i]]);
sum:=sum+tot[num[i]]*money[num[i]];
end; //read data
fillchar(f,sizeof(f),5);
ans:=maxLongint;
dfs(1,sum); //dg
writeln(ans);
end.
当然这道题目还可以优化一下,就是当某些优化价根本用不上的时候,就可以把它筛掉,不用dg了。
例如
某优惠价
1 2 2 3 10
1 4 2 6 21
第2个就肯定没用了,还有可能是优惠价i比优惠价j+原价购买还要多,也筛掉。
这里不提供代码,因为加了这个优化并不会优化太多。