【USACO题库】3.3.2 Shopping Offers商店购物

题目描述


在商店中,每一种商品都有一个价格(用整数表示)。例如,一朵花的价格是 2 zorkmids (z),而一个花瓶的价格是 5z 。为了吸引更多的顾客,商店举行了促销活动。
促销活动把一个或多个商品组合起来降价销售,例如:
三朵花的价格是 5z 而不是 6z,
两个花瓶和一朵花的价格是 10z 而不是 12z。

编写一个程序,计算顾客购买一定商品的花费,尽量利用优惠使花费最少。尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做。
对于上面的商品信息,购买三朵花和两个花瓶的最少花费是:以优惠价购买两个花瓶和一朵花(10z),以原价购买两朵花(4z)。

PROGRAM NAME: shopping
INPUT FORMAT
输入文件包括一些商店提供的优惠信息,接着是购物清单。
第一行
优惠商品的种类数(0 <= s <= 99)。
第二行..第s+1 行
每一行都用几个整数来表示一种优惠方式。第一个整数 n (1 <= n <= 5),表示这种优惠方式由 n 种商品组成。后面 n 对整数 c 和 k 表示 k (1 <= k <= 5)个编号为 c (1 <= c <= 999)的商品共同构成这种优惠,最后的整数 p 表示这种优惠的优惠价(1 <= p <= 9999)。优惠价总是比原价低。
第 s+2 行
这一行有一个整数 b (0 <= b <= 5),表示需要购买 b 种不同的商品。
第 s+3 行..第 s+b+2 行
这 b 行中的每一行包括三个整数:c ,k ,和 p 。c 表示唯一的商品编号(1 <= c <= 999),k 表示需要购买的 c 商品的数量(1 <= k <= 5)。p 表示 c 商品的原价(1 <= p <= 999)。最多购买 5*5=25 个商品。

SAMPLE INPUT (file shopping.in)
2
1 7 3 5
2 7 1 8 2 10
2
7 3 2

8 2 5


OUTPUT FORMAT
只有一行,输出一个整数:购买这些物品的最低价格。

SAMPLE OUTPUT (file shopping.out)

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+原价购买还要多,也筛掉。

这里不提供代码,因为加了这个优化并不会优化太多。


你可能感兴趣的:(【USACO题库】3.3.2 Shopping Offers商店购物)