题目
这是一道购物分配的算法题目,题目如下:
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,然后再沿用上面代码就可以了。
总结
总之,第一种方法简单粗暴易于理解,但是循环次数过多,一旦数量大就会影响程序的性能,而第二种方法需要有一定的计算理解能力,相对会比较难一些,相信这篇文章能帮到别人,有问题还请指出。