【八月刷题打卡】商店购物

228 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情

[USACO3.3]商店购物 Shopping Offers

题目背景

在商店中,每一种商品都有一个价格(用整数表示)。例如,一朵花的价格是 22 ,而一个花瓶的价格是 55 。为了吸引更多的顾客,商店举行了促销活动。

题目描述

促销活动把一个或多个商品组合起来降价销售,例如:

三朵花的价格是 55 而不是 6622 个花瓶和一朵花的价格是 1010 而不是 1212 。 请编写一个程序,计算顾客购买一定商品的花费,尽量地利用优惠使花费最少。尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做。

对于上面的商品信息,购买三朵花和两个花瓶的最少花费的方案是:以优惠价购买两个花瓶和一朵花(1010),以原价购买两朵花(44)。

输入格式

输入文件包括一些商店提供的优惠信息,接着是购物清单。(最多有 55 种商品)

第一行 优惠方案的种类数(0s990\leq s\leq99)。

22\sims+1s+1 行 每一行都用几个整数来表示一种优惠方式。第一个整数 nnn5\leq n\leq5),表示这种优惠方式由 nn 种商品组成。后面 nn 对整数 cckk 表示 kk1k51\leq k\leq5)个编号为 cc1c9991\leq c\leq999)的商品共同构成这种优惠,最后的整数 pp 表示这种优惠的优惠价(1p9,9991\leq p\leq9,999)。优惠价总是比原价低。

s+2s+2 行 这一行有一个整数 bb0b50\leq b\leq5),表示需要购买 bb 种不同的商品。

s+3s+3\sims+b+2s+b+2 行 这 bb 行中的每一行包括三个整数:c,k,pc,k,pcc 表示唯一的商品编号(1c9991\leq c\leq999),kk 表示需要购买的 cc 商品的数量(1k51\leq k\leq5)。pp 表示 cc 商品的原价(1p9991\leq p\leq999)。最多购买 5×5=255\times5=25 个商品。

输出格式

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

样例 #1

样例输入 #1

2
1 7 3 5
2 7 1 8 2 10
2
7 3 2
8 2 5

样例输出 #1

14

提示

题目翻译来自NOCOW。

USACO Training Section 3.3

#include<bits/stdc++.h>
using namespace std;
const int S=100+5,N=10,P=10000+5,C=1000+5;
int sale[S],sp[S],sta=0,f[50000],pri[N],cnt=0,s,b,c,k,p;
//优惠的状态 各优惠花的钱 目标状态 各个状态的最小花费 各个商品的单价 总有多少种商品
int base[N],cd[50000];
//六进制的转化 离散化
template<class t>void rd(t &x)
{//快读
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

bool jud(int st,int x[N])
{
    int cur=0;
    while(st)
    {
        if((st%6)>x[++cur]) return 0;
        st/=6;
    }
    return 1;
}

int main()
{
    memset(cd,0,sizeof(cd));
    memset(sale,0,sizeof(sale));
    base[1]=1;
    for(int i=2;i<=6;++i) base[i]=base[i-1]*6;//初始化
    rd(s);
    for(int i=1;i<=s;++i)
    {
        int n;rd(n);
        for(int j=1;j<=n;++j)
        {
            rd(c),rd(k);
            if(!cd[c]) cd[c]=++cnt;
            sale[i]+=base[cd[c]]*k;//各个优惠的对应状态
        }
        rd(sp[i]);
    }
    rd(b);
    for(int i=1;i<=b;++i)
    {
        rd(c),rd(k),rd(p);
        if(!cd[c]) cd[c]=++cnt;
        sta+=base[cd[c]]*k,pri[cd[c]]=p;
    }
    for(int ss=1;ss<=sta;++ss)
    {//枚举各种状态
        int pro[N],nw=ss,cur=0;//处理出当前状态所包含的产品及其数量
        while(nw) pro[++cur]=nw%6,nw/=6;
        for(int i=1;i<=cur;++i) f[ss]+=pro[i]*pri[i];
        //算不用优惠直接单买的价格
        for(int i=1;i<=s;++i)//枚举各个优惠
        if(ss>=sale[i]&&jud(sale[i],pro))//判断其是否可用即不能添加商品
        f[ss]=min(f[ss],f[ss-sale[i]]+sp[i]);
    }
    printf("%d",f[sta]);
    return 0;
}