【DP-完全背包-离散化】USA3.1——商店购物 Shopping Offers

mac2025-01-08  15

前言

如果熟练掌握背包等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...

最新回复(0)