
本文介绍一种基于预算约束的穷举算法,用于计算三种预包装食品(香肠、汉堡、弗里卡德尔)在给定金额下的所有整数包数组合,并转换为实际单品数量输出。
本文介绍一种基于预算约束的穷举算法,用于计算三种预包装食品(香肠、汉堡、弗里卡德尔)在给定金额下的所有整数包数组合,并转换为实际单品数量输出。
要解决“在固定预算下枚举所有可行食品组合”这一问题,核心在于将现实约束建模为数学不等式,并通过系统性遍历满足条件的整数解。本例中,三种食品以固定规格销售:
- Worst(香肠):6 根/包,单价 €5
- Hamburger(汉堡):20 个/包,单价 €10
- Frikandel(弗里卡德尔):25 根/包,单价 €15
目标是:输入预算(如 €200),输出所有满足 5×w + 10×h + 15×f ≤ budget 的非负整数三元组 (w, h, f),并按 w×6 根香肠、h×20 个汉堡、f×25 根弗里卡德尔格式展示。
以下是一个清晰、可扩展的实现方案(已优化原始暴力循环逻辑,增强可读性与健壮性):
<?php // 从标准输入读取预算(支持命令行交互)
if (PHP_SAPI === 'cli') {
fwrite(STDOUT, "请输入预算(欧元): ");
$budget = (int)trim(fgets(STDIN));
if ($budget <= 0) {
die("预算必须为正整数。\n");
}
} else {
$budget = 200; // Web 环境默认值,生产环境建议通过表单传入
}
// 定义商品信息:[名称, 单价, 单包数量]
$items = [
['worst', 5, 6], // 香肠
['hamburger', 10, 20], // 汉堡
['frikandel', 15, 25] // 弗里卡德尔
];
echo "预算 €{$budget} 下的所有可行组合:\n";
echo str_repeat("-", 50) . "\n";
$combinations = [];
// 三层嵌套循环(按价格升序排列,提升剪枝效率)
for ($w = 0; ; $w++) {
$costW = $w * $items[0][1];
if ($costW > $budget) break;
for ($h = 0; ; $h++) {
$costH = $costW + $h * $items[1][1];
if ($costH > $budget) break;
for ($f = 0; ; $f++) {
$total = $costH + $f * $items[2][1];
if ($total > $budget) break;
// 记录满足预算的组合(包数)
$combinations[] = [$w, $h, $f];
}
}
}
// 输出转换为实际单品数量,并格式化显示
foreach ($combinations as $combo) {
[$w, $h, $f] = $combo;
printf("• %d %s, %d %s, %d %s\n",
$w * $items[0][2], $items[0][0] . (plural($w * $items[0][2]) ? 's' : ''),
$h * $items[1][2], $items[1][0] . (plural($h * $items[1][2]) ? 's' : ''),
$f * $items[2][2], $items[2][0] . (plural($f * $items[2][2]) ? 's' : '')
);
}
// 辅助函数:英文复数处理(简化版)
function plural($n) {
return $n != 1;
}
// 可选:统计总数
echo str_repeat("-", 50) . "\n";
echo "共找到 " . count($combinations) . " 种组合。\n";
?>
✅ 关键设计说明:
- 避免无限循环:外层循环条件由 break 显式控制,确保在成本超限时立即终止;
- 内存友好:不预先生成全量排列,而是边计算边输出,适用于中等预算(如 €500 内);
- 可扩展性强:只需修改 $items 数组即可适配新增品类或价格调整;
- 用户交互友好:CLI 模式支持 readline 输入,Web 模式可无缝对接表单;
- 输出语义准确:“6 worsten” 表示 6 包香肠(即 36 根),而非 6 根——严格遵循题设单位逻辑。
⚠️ 注意事项:
- 高预算(如 €1000+)会导致组合数指数级增长,建议添加最大组合数限制(如 count($combinations) > 10000 && die("结果过多,请缩小预算"));
- 实际部署时应校验输入合法性(如非数字、负数、超长字符串);
- 若需最优解(如最大化单品总数),应改用动态规划或线性整数规划,而非穷举。
该方案摒弃了原代码中混淆的排列生成逻辑(cmb() 和 pc_permute() 仅生成价格排列,与预算无关),转而聚焦于约束满足问题的本质——这是组合优化入门的经典实践。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











