前言
如果熟练掌握背包等DP的运用的话,这道题很水的
不过我是不会说我因为一个“ * ”打成了“ + ”改了一晚上的qwq...
题目
题目背景
在商店中,每一种商品都有一个价格(用整数表示)。例如,一朵花的价格是 2 zorkmids (z),而一个花瓶的价格是 5z 。为了吸引更多的顾客,商店举行了促销活动。
题目描述
促销活动把一个或多个商品组合起来降价销售,例如:
三朵花的价格是 5z 而不是 6z, 两个花瓶和一朵花的价格是 10z 而不是 12z。 编写一个程序,计算顾客购买一定商品的花费,尽量利用优惠使花费最少。尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做。
对于上面的商品信息,购买三朵花和两个花瓶的最少花费的方案是:以优惠价购买两个花瓶和一朵花(10z),以原价购买两朵花(4z)。
输入格式
输入文件包括一些商店提供的优惠信息,接着是购物清单。(最多有5种商品)
第一行 优惠方案的种类数(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 个商品。
输出格式
只有一行,输出一个整数:购买这些物品的最低价格。
输入输出样例
输入
2
1 7 3 5
2 7 1 8 2 10
2
7 3 2
8 2 5
输出
14
说明/提示
题目翻译来自NOCOW。
USACO Training Section 3.3
题目大意
有一些优惠方案,买指定商品的指定个数便能享更优惠的价格,问恰好买给出的商品的指定个数,最少花多少钱
分析
要求买指定商品的指定数量+花钱最少:【完全背包】板题
本题有两个特点:
1.最多购买5种商品,商品编号为1~999
2.每种商品最多买5件
于是:
1.将商品编号离散化,变成1~5
2.根据范围可以做【5维DP】:
dp[ i1 ][ i2 ][ i3 ][ i4 ][ i5 ]:第一种商品买i1件、第二种买i2件...第五种买i5件,总共的价钱
dp[ i1 ][ i2 ][ i3 ][ i4 ][ i5 ]=
min { dp[ i1 ][ i2 ][ i3 ][ i4 ][ i5 ] ,
dp[ i1 - a[ i ].num[ 1 ] ][ i2 - a[ i ].num[ 2 ] ][ i3 - a[ i ].num[ 3 ] ][ i4 - a[ i ].num[ 4 ] ][ i5 - a[ i ].num[ 5 ] ]+a[ i ].p }
其中a[ i ].num[ j ]指第i种优惠方案要买 j 号商品num[ j ]件,a[ i ].p指第 i 种优惠方案的价钱
代码
/*
ID:lunasmi2
TASK:shopping
LANG:C++
*/
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=10000;
int f[MAXN+5],need[100+5],p[100+5];
int dp[10][10][10][10][10];
int n,m,cnt,tot;
struct node
{
int p;//优惠价格
int num[100+5];//该优惠方案的商品数量
}a[100+5];
int Solve()
{
//初始化:不用优惠购买商品,所花的钱数
for(int i1=0;i1<=need[1];i1++)
for(int i2=0;i2<=need[2];i2++)
for(int i3=0;i3<=need[3];i3++)
for(int i4=0;i4<=need[4];i4++)
for(int i5=0;i5<=need[5];i5++)
dp[i1][i2][i3][i4][i5]=i1*p[1]+i2*p[2]+i3*p[3]+i4*p[4]+i5*p[5];
for(int i=1;i<=n;i++)//n种优惠方案
{
for(int i1=a[i].num[1];i1<=need[1];i1++)
for(int i2=a[i].num[2];i2<=need[2];i2++)
for(int i3=a[i].num[3];i3<=need[3];i3++)
for(int i4=a[i].num[4];i4<=need[4];i4++)
for(int i5=a[i].num[5];i5<=need[5];i5++)
dp[i1][i2][i3][i4][i5]=min(dp[i1][i2][i3][i4][i5],dp[i1-a[i].num[1]][i2-a[i].num[2]][i3-a[i].num[3]][i4-a[i].num[4]][i5-a[i].num[5]]+a[i].p);
}
return dp[need[1]][need[2]][need[3]][need[4]][need[5]];
}
int main()
{
//freopen("shopping.in","r",stdin);
//freopen("shopping.out","w",stdout);
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++)
{
scanf("%d",&tot);
for(int j=1;j<=tot;j++)
{
scanf("%d",&x);
if(!f[x])
f[x]=++cnt;
x=f[x];
scanf("%d",&a[i].num[x]);
}
scanf("%d",&a[i].p);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
if(!f[x])
f[x]=++cnt;
x=f[x];
scanf("%d%d",&need[x],&p[x]);
}
printf("%d\n",Solve());
return 0;
}
总结
我在DP方面还需加强...背包什么的几乎都还给老师了QAQ...