商店购物题解

题目大意:

在商店中,每一种商品都有一个价格

商店 把一个或多个商品组合起来降价销售,形成优惠方案

编写一个程序,计算顾客购买一定商品的花费,利用优惠使花费最少。

** 尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做。**


解析题目:

这道题就是五维暴力,但 易错点很多,恶心,是道毒瘤题

不愧是IOI的真题

暴力,数据较小,且最多五种商品

注意!尽管有时候添加其他商品可以获得更少的花费,但是你不能这么做

比如你要买三个苹果,两根香蕉,花了11z

方案是三个苹果,三根香蕉花了10z

那也不行,因为浪费了一根香蕉

(宣传不浪费的IOI)

状态:\(f_{i,j,k,l,q}\)表示 买 i 的第一种商品 ,买 j 的第二种商品 ,买 k 的第三种商品 ,买 l 的第四种商品 ,买 q 的第五种商品 的最小花费

如果不足五种怎么办?其实不慌,比如如果有三种 ,l,q将一直等于0,不影响使用

我们还需要一个二维数组p,\(p_{i,j}\)表示第i种优惠里商品j所需的数量。

模拟即可


详细讲解:

先来介绍一下没什么用快读吧

C++ 中,读入字符要比读入数字快

因此,我们可以读入字符,将其转为数字

在一百万次输入后,快读将比scanf快1秒

其实这道题不用快读,是我打时不知道怎么想的

inline int read() 
{
    int ans = 0;
    char c = getchar();
    while ((c < '0' || c > '9') )//筛掉空格、换行等 
	{
		c = getchar();
	}
    ans = c - '0';//正式开始读入 
	c = getchar();
    while (c >= '0' && c <= '9') 
	{
		ans = (ans << 3) + (ans << 1);//位运算比正常计算快,这个位运算等价于ans*=10; 
		ans += c - '0'; 
		c = getchar();
	}
    return ans;
}//总之就生活小妙招了属于是

见样例,虽然 只有5种,

但编号不一定是1~5,我们需要在输入自行编号,一个h数组即可,map会WA

由于一个编号会出现多次,要先判断h[x]是否为0,是0才编号

for(int i=1;i<=s;i++)//s是方案数
	{
		n=read();
		for(int j=1;j<=n;j++)
		{
			b=read();
			if(h[b]==0)h[b]=++tmp;//编号
			p[i][h[b]]=read();
		}
		money[i]=read();//money是 优惠方案的价钱 的意思 
	}

在下面也是一样的

for(int i=1;i<=b;i++)//b是我们要买的种类数
	{
		int x=read(); 
		if(h[x]==0)h[x]=++tmp;
		//同上,是0才编号 
		need[h[x]]=read(); //need表示我们一共需要多少个 
		old[h[x]]=read();//old 表示原价 
	}

接下来是初始化

默认是全用原价

for(int i=0;i<=need[1];i++)
	{
		for(int j=0;j<=need[2];j++)
		{
			for(int k=0;k<=need[3];k++)
			{
				for(int l=0;l<=need[4];l++)
				{
					for(int q=0;q<=need[5];q++)//五重暴力初始化,求出所有的原价
											   //注意也要考虑0,不买也不是不行 
					{
						 f[i][j][k][l][q]=old[1]*i+old[2]*j+old[3]*k+old[4]*l+old[5]*q;
					}						 
				}			 
			}			 
		} 		 
	}

谁写的顺口溜?


接下来是可怕的六重循环解析

for(int m=1;m<=s;m++)
     {

代码:我裂开了

m表示当前考虑的方案

然后继续看

我们要枚举i,j,k,l,q

对于范围,不足 p[m]就不能实现方案了,超过need就浪费了

所以是p[m]~need

for(int i=p[m][1];i<=need[1];i++)
		{
			for(int j=p[m][2];j<=need[2];j++)
			{
				for(int k=p[m][3];k<=need[3];k++)
				{
					for(int l=p[m][4];l<=need[4];l++)
					{
						for(int q=p[m][5];q<=need[5];q++)//从i到q都一样,只是表示的 要买的东西 不同

解析一下转移方程

当求 \(f_{i,j,k,l,q}\)时,

应该将其分解成子问题

显然,我们只用考虑 卖完还需要的东西构成的子问题 加上 方案价格比较大小 即可

{  
						if(f[i][j][k][l][q]>=f[i-p[m][1]][j-p[m][2]][k-p[m][3]][l-p[m][4]][q-p[m][5]]+money[m])
						{
					 		f[i][j][k][l][q]=f[i-p[m][1]][j-p[m][2]][k-p[m][3]][l-p[m][4]][q-p[m][5]]+money[m];
						}		
					}

别忘了括号

}			 
		}			 
	} 		 
} 			
}

你可能感兴趣的:(蓝桥杯,算法,数据结构,职场和发展)