购物分配算法问题


题目

这是一道购物分配的算法题目,题目如下:
100块钱去超市买日用品,牙膏10元一支,毛巾5元一条,牙刷2元一只,每种商品至少要买一件,请问将这一百块钱花完,有多少种购买方案?


解决方法

这里提供两种解题方案,其中第一种比较简单用的比较多,第二种是我花费时间想出来的方法,代码量和计算量要小一些,但也比较难理解。

方法一:穷举法

具体思路

先根据每一种商品的单价,算出满足100元购物的最大购物数量

牙膏:1支10元,总共100元,最大购物量为100 / 10 = 10,因此牙膏最多只能买10支;
毛巾:1支5元,总共100元,最大购物量为100 / 5 = 20,因此牙膏最多只能买20支;
牙刷:1支2元,总共100元,最大购物量为100 / 2 = 50,因此牙膏最多只能买50支;

然后可以使用三重循环嵌套,将每一种商品可能购买的数量遍历一遍,当三中商品购买的金额相加等于100时,则表示购物方案成立。

代码如下

var sum = 0;

//遍历牙膏的所有可能的购买数量
for (var i = 1; i <= 10; i++) {
	//遍历毛巾的所有可能的购买数量
	for (var j = 1; j <= 20; j++) {
		//遍历牙刷的所有可能的购买数量
		for (var k = 1; k <= 50; k++) {
			//当三种商品的购物金额总和等于100时,表示方案成立
			if (i * 10 + j * 5 + k * 2 == 100) {
				sum++;
				break;
			}
		}
	}
}

console.log(sum);

方法二:单位转换运算

具体思路

将毛巾和牙刷转换为和牙膏相同的单位,再进行统一分配,根据题目可知:
一条牙膏为10元,10条牙膏刚好达到100元;
一条毛巾为5元,我们会发现毛巾不能以单数为购买数量,因为毛巾购买量为单数的话,与牙膏和牙刷相加是无法满足满100元的要求;
一根牙刷为2元,同理我们也会发现,牙刷购买量必须为5的倍数,否则与牙膏和毛巾相加无法满足满100元的要求。
这时我们发现,一条牙膏为10元,两条毛巾为10元,5根牙刷也为10元,即我们可以将毛巾和牙刷分别转换成和牙膏一样的单位,因此转换如下:

单价 * 数量 = 金额
牙膏:10 * 10 = 100元
毛巾:(5 * 2) * (20 / 2) = 100元(毛巾每2条为一组,因此20 / 2,每一组毛巾的价格为单价的2倍)
牙刷:(2 * 5) * (50 / 5) = 100元(牙刷每5条为一组,因此50 / 5,每一组牙刷的价格为单价的5倍)

这时我们发现,三种商品都转换成了牙膏,由前面的计算我们得出,当牙膏购买量为10时,刚好金额满足100元,因此只要三种商品的购物量相加等于10即可以满足题目要求,我们分别将三种牙膏商品的购买量设为三个未知数x、y、z,得到以下式子:

x + y + z = 10

只要x、y、z之和等于10,则购物方案成立。

代码如下

var sum = 0;
//x是第一种牙膏商品的取值,y是第二种牙膏商品的取值,由于第三种牙膏商品的取值必然是10 - x - y,因此没必要声明,也就是说只要知道了x和y的值,就能知道第三种商品的值
var x = 1, y = 1;

//对第一种商品可能取的值进行遍历
for (; x < 10; x++) {
	//算出x每次遍历时y的取值,10为x、y、z之和,10 - x得出的值由y和z分配,-1是为了不让z出现取值为0的情况
	y = 10 - x - 1;
	//避免y取值为0
	if (y != 0) {
		sum += y;
	}
}

console.log(sum);

哈哈,代码是不是很简单,但是却难以理解,其实还有一种更快的思路,咱们回到最开始的时候:

单价 * 数量 = 金额
牙膏:10 * 10 = 100 =>毛巾:5 * 20 = 100 => 牙刷:2 * 50 = 100
由于三种商品的最大购买量金额都为100,可以转换为:
10 * 10 => 10 * 10 => 10 * 10 = 100

这时三种商品都是等价的10 * 10,然后再沿用上面代码就可以了。


总结

总之,第一种方法简单粗暴易于理解,但是循环次数过多,一旦数量大就会影响程序的性能,而第二种方法需要有一定的计算理解能力,相对会比较难一些,相信这篇文章能帮到别人,有问题还请指出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值