[蓝桥杯][算法提高VIP]促销购物

题目描述
张超来到了超市购物。
每个物品都有价格,正好赶上商店推出促销方案。就是把许多东西一起买更便宜(保证优惠方案一定比原价便宜)。物品要买正好的个数,而且不能为了便宜而买不需要的物品。
张超拿到了优惠方案,和需要购买的物品清单,当然想求出最小的花费。他是信息学选手,自然地想到写个程序解决问题。
输入
第一行促销物品的种类数(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 个商品。
输出
一个整数ans,表示需要花的最小费用
样例输入
2
1 7 3 5
2 7 1 8 2 10
2
7 3 2
8 2 5
样例输出
14

//完全背包的变形,动态规划
#include <iostream>
#include <algorithm>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;

struct node1{
	int num[1005]; //为此方案里编号为k的数量
	int money;     //此方案的价格; 
}pa[100]; //方案打包 
 
struct node2{ //单品的情况 
	int c,k,p;
}pb[10];

int n,m,res[6][6][6][6][6];

int main()
{
	scanf("%d",&n);
	
	int i,j;
	
	for(i = 0;i<n;i++)
	{
		int t;
		scanf("%d",&t);
		for(j = 0;j<t;j++)
		{
			int k,l;
			scanf("%d%d",&k,&l);
			pa[i].num[k] = l;
		}
		scanf("%d",&pa[i].money);
	}
	scanf("%d",&m);
	
	for(i = 0;i<m;i++)
	{
		scanf("%d%d%d",&pb[i].c,&pb[i].k,&pb[i].p);
		pa[n].money = pb[i].p;
		pa[n++].num[pb[i].c] = 1;
	}
	memset(res,INF,sizeof(res));
	
	res[0][0][0][0][0] = 0;    //动态规划的初始化 
    
	int b1,b2,b3,b4,b5,m1,m2,m3,m4,m5;
    for(i = 0;i<n;i++)
    {
    	m1 = pa[i].num[pb[0].c];
    	m2 = pa[i].num[pb[1].c];
    	m3 = pa[i].num[pb[2].c];
    	m4 = pa[i].num[pb[3].c];
    	m5 = pa[i].num[pb[4].c];
    	for(b1 = m1;b1<=pb[0].k;b1++)    //完全背包与0-1背包的区别是可以重复装一样的物品,所以从下网上循环,而0-1背包则需要从上往下 
    	 for(b2 = m2;b2<=pb[1].k;b2++)
    	  for(b3 = m3;b3<=pb[2].k;b3++)
    	   for(b4 = m4;b4<=pb[3].k;b4++)
    	    for(b5 = m5;b5<=pb[4].k;b5++)
    	     res[b1][b2][b3][b4][b5] = min(res[b1][b2][b3][b4][b5],res[b1-m1][b2-m2][b3-m3][b4-m4][b5-m5]+pa[i].money);//等价于装背包 

	}
	printf("%d\n",res[pb[0].k][pb[1].k][pb[2].k][pb[3].k][pb[4].k]);
	
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值