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

前言

如果熟练掌握背包等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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值