R语言求解单目标背包问题:返回总天数为7的所有菜品组合方案
解决方案
你需要的是0-1背包问题的所有可行解枚举,而非单一最优解。由于你当前的菜品总数仅9种,全量枚举所有子集的方案实现最简单、计算成本极低,完全可以满足需求:
方案1:全量枚举(适合菜品数≤15的场景)
不需要引入额外第三方包,用R基础语法即可实现:
# 沿用你之前的基础数据 dish <-c('Schnitzel','Burger','Steak','Salad','Falafel','Salmon','Mashed potatoes','MacnCheese','Hot Dogs') days_the_food_lasts <- c(2,2,1,1,3,1,2,2,4) price_of_the_food <- c(20,20,40,10,15,18,10,15,15) data <- data.frame(dish, days_the_food_lasts, price_of_the_food) target_days <- 7 # 生成所有选/不选的组合(每个菜品对应一列,TRUE=选中,FALSE=不选) all_combinations <- expand.grid(rep(list(c(FALSE, TRUE)), nrow(data))) # 去掉全不选的无效组合 all_combinations <- all_combinations[rowSums(all_combinations) > 0, ] # 计算每个组合的总天数,筛选出刚好等于目标天数的 valid_mask <- apply(all_combinations, 1, function(row) sum(data$days_the_food_lasts[row]) == target_days) valid_combinations <- all_combinations[valid_mask, ] # 把结果转换成易读的菜品列表格式 result <- lapply(1:nrow(valid_combinations), function(i) { selected_rows <- as.logical(valid_combinations[i, ]) data[selected_rows, ] }) # 测试输出第一个组合 print(result[[1]]) # 查看总符合条件的组合数量 cat("总共有", length(result), "种符合要求的菜品组合\n")
运行后result列表里的每个元素就是一个总天数恰好为7的菜品组合,你可以按需提取每个组合的菜品名、总价等信息,也可以扩展筛选逻辑,比如增加总价格上限、必须包含指定菜品等规则。
方案2:回溯剪枝(适合菜品数≥15的场景)
如果后续你的菜品库扩容到20种以上,全量枚举的时间成本会指数级上升,此时可以用回溯剪枝方法,提前终止总天数已经超过7的分支,大幅减少计算量:
result <- list() backtrack <- function(start_idx, current_days, selected) { # 总天数刚好符合要求,存入结果 if (current_days == target_days) { result <<- append(result, list(data[selected, ])) return() } # 总天数超出上限/遍历完所有菜品,终止分支 if (current_days > target_days || start_idx > nrow(data)) { return() } # 分支1:选中当前菜品 backtrack(start_idx + 1, current_days + data$days_the_food_lasts[start_idx], c(selected, start_idx)) # 分支2:不选当前菜品 backtrack(start_idx + 1, current_days, selected) } # 启动回溯 backtrack(1, 0, c())
内容的提问来源于stack exchange,提问作者cgpb
相关产品推荐
相关产品推荐

