携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情
[USACO3.3]商店购物 Shopping Offers
题目背景
在商店中,每一种商品都有一个价格(用整数表示)。例如,一朵花的价格是 ,而一个花瓶的价格是 。为了吸引更多的顾客,商店举行了促销活动。
题目描述
促销活动把一个或多个商品组合起来降价销售,例如:
三朵花的价格是 而不是 , 个花瓶和一朵花的价格是 而不是 。 请编写一个程序,计算顾客购买一定商品的花费,尽量地利用优惠使花费最少。尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做。
对于上面的商品信息,购买三朵花和两个花瓶的最少花费的方案是:以优惠价购买两个花瓶和一朵花(),以原价购买两朵花()。
输入格式
输入文件包括一些商店提供的优惠信息,接着是购物清单。(最多有 种商品)
第一行 优惠方案的种类数()。
第 行 第 行 每一行都用几个整数来表示一种优惠方式。第一个整数 (),表示这种优惠方式由 种商品组成。后面 对整数 和 表示 ()个编号为 ()的商品共同构成这种优惠,最后的整数 表示这种优惠的优惠价()。优惠价总是比原价低。
第 行 这一行有一个整数 (),表示需要购买 种不同的商品。
第 行 第 行 这 行中的每一行包括三个整数: 。 表示唯一的商品编号(), 表示需要购买的 商品的数量()。 表示 商品的原价()。最多购买 个商品。
输出格式
只有一行,输出一个整数:购买这些物品的最低价格。
样例 #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;
}