
本文介绍如何在给定预算下,枚举所有满足价格约束的食品包组合方案,并按实际单件数量(如6根香肠/包、20个汉堡/包)输出可读结果,避免暴力全排列,采用高效递增迭代策略。
本文介绍如何在给定预算下,枚举所有满足价格约束的食品包组合方案,并按实际单件数量(如6根香肠/包、20个汉堡/包)输出可读结果,避免暴力全排列,采用高效递增迭代策略。
要解决“在固定预算内找出所有可行食品采购组合”这一问题,核心不是排列价格(如 5,10,15),而是枚举每种食品包的购买数量,使其总价 ≤ 预算,并将包数换算为实际单品数(例如:1包香肠 = 6根,故 n 包 → n × 6 根)。原始代码误将价格数组当作排列对象,导致输出无意义的数字序列;正确思路是使用嵌套循环或状态递增法遍历合法的 (worst_pack, burger_pack, frikandel_pack) 三元组。
以下是一个清晰、可控、可扩展的实现方案:
<?php // 定义商品单价(每包)与单包包含量
$prices = [
'worst' => 5, // 每包 6 根,¥5
'hamburger' => 10, // 每包 20 个,¥10
'frikandel' => 15 // 每包 25 根,¥15
];
$units = [
'worst' => 6,
'hamburger' => 20,
'frikandel' => 25
];
// 从标准输入读取预算(兼容 CLI 环境)
if (PHP_SAPI === 'cli') {
fwrite(STDOUT, "请输入预算(欧元): ");
$budget = (int)trim(fgets(STDIN));
if ($budget $w * $units['worst'],
'hamburger' => $h * $units['hamburger'],
'frikandel' => $f * $units['frikandel'],
'cost' => $total
];
}
}
}
}
// 输出格式化结果(按成本升序,增强可读性)
usort($combinations, fn($a, $b) => $a['cost'] $b['cost']);
foreach ($combinations as $i => $combo) {
echo sprintf(
"• %d worsten, %d hamburgers, %d frikandellen (花费 ¥%d)\n",
$combo['worst'],
$combo['hamburger'],
$combo['frikandel'],
$combo['cost']
);
}
echo "\n共找到 " . count($combinations) . " 种可行组合。\n";
?>
✅ 关键设计说明:
- 避免排列陷阱:不 shuffle 或 permute 价格,而是枚举各商品包的购买数量(整数非负),确保解空间物理可实现;
- 单位自动换算:用 $units 数组解耦「包」与「单品」,输出直接展示终端用户关心的 worsten/hamburgers 数量;
- 预算严格约束:内层循环上限由剩余预算动态计算($max_f),杜绝无效迭代;
- CLI 友好:使用 fgets(STDIN) 读取交互式输入,适配命令行场景;
- 可扩展性强:新增品类只需向 $prices 和 $units 添加键值对,循环结构无需修改。
⚠️ 注意事项:
- 当预算较大(如 >€500)且品类增多时,三层循环可能性能下降;此时建议改用回溯剪枝或动态规划生成最优子集;
- 实际部署中应加入输入校验(如非数字、负数、超长输入);
- 若需限制最小/最大单品数(如“至少100个汉堡”),可在循环体内添加 continue 条件过滤。
该方案直击问题本质——在整数线性约束下枚举可行解,输出直观、逻辑透明、易于维护,是典型背包类问题的轻量级实践范例。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











