假设我有100个产品的清单,每个产品都有价格。每个还具有能量(kJ)测量值。
是否有可能找到15种产品的最佳组合,其中10美元以下的能量总和(kJ)最大,使用编程?
我知道C#,但任何语言都没问题。欢呼声。
更新:稍微有点发现背包问题的示例源代码。有没有人知道在哪里找到一些。谷歌搜索了几个小时,如果可能的话,需要在明天之前进行排序。 TA
答案 0 :(得分:14)
http://en.wikipedia.org/wiki/Knapsack_problem
背包问题或背包问题是combinatorial optimization中的一个问题:给定一组项目,每个项目都有一个权重和一个值,确定数字每个项目包括在一个集合中,以使总重量小于或等于给定的限制,并且总值尽可能大。它的名字源于受固定大小knapsack约束的人所面临的问题,并且必须填写最有价值的物品......
答案 1 :(得分:6)
这听起来更像linear programming问题。
非正式地,线性编程 决定实现最佳的方式 结果(如最大利润或 给定数学中的最低成本) 模型和给出一些列表 要求表示为线性的 方程。
答案 2 :(得分:4)
这在整数线性规划中,优化受线性约束的线性方程,其中所有变量和系数都是整数。
对于 i 的所有值,你想要变量includeItem1,...,includeItemN,约束0≤includeItem i ≤1,includeItem1 + ... +includeItemN≤ 15,includeItem1 * priceItem1 + ...≤10,最大化includeItem1 * kilojouleItem1 + ....
将其粘贴在您最喜欢的整数线性程序求解器中并获得解决方案:)
另见http://en.wikipedia.org/wiki/Linear_programming
说你的特定问题是NP完全没有意义,但它是NP完全(某种)问题的一个实例,所以理论上可能没有 快这样做的方式。根据您希望获得的最佳性和ILP求解器的工作速度有多接近,这在实践中可能是可行的。
我认为你的问题不是ILP的一个特例,它使得它特别容易解决。将它视为背包式问题,您可以限制自己查看1..100的所有子集,这些子集最多(或精确地)有15个元素,这是n的多项式 - 它是n-choose-15,它小于(n ^ 15)/(15!),但是当n = 100时,这并不是非常有用。
如果您需要求解器程序的建议,我尝试过glpk并发现它使用起来很愉快。如果你想要一些花钱的东西,我的讲师总是以CPLEX为例。
答案 3 :(得分:1)
这听起来很像背包问题。有各种方法(例如,按能量密度递减的顺序)。
答案 4 :(得分:1)
如果您可以选择产品,这是背包问题。如果您可以选择产品的小数值,那么您可以使用单纯形法解决这个问题,但分数背包问题有一个简单的解决方案。
按能源/价格比率订购商品,挑选最高价格的100%,直到您用完为止,然后选择剩余最高价格的小数值。
例如,如果价格是4,3,5,4,能量是3,5,2,7,则订购
7 / 4,5 / 3,3 / 4,2 / 5
所以你会选择4美元和2美元,这将花费7美元,剩下的3美元你将购买第一件商品的75%,价格为3美元,能量为3 * .75 = 2.25
这将使总能量为14.25
请注意,允许小数值会提供比仅允许0%或100%更高的目标值,因此没有整数解决方案会比14.25更好(或者因为目标值必须是整数,所以14或更好)
要解决原始的背包问题,你可以使用分支定界,这在实践中应该可以正常工作。假设您有一个目标值为z *
的当前候选解决方案请注意,当您创建必须选择项目的子问题时,只需从预算中减去其价格并将该值添加到利润中,现在您需要解决较小的问题。
有关更详细的说明,请查看维基百科上的Branch and Bound。
答案 5 :(得分:1)
Stony Brook算法存储库列出implementations for the knapsack problem.
他们的书The Algorithm Design Manual有大量问题的这类信息。
答案 6 :(得分:1)
是的,正如每个人都指出这是一个复杂的背包问题。这个简单的东西虽然可能很好......
SELECT TOP 15 *
FROM Product
WHERE Price < 10
ORDER BY Energy DESC
答案 7 :(得分:0)
这让我想起了着名的背包算法
答案 8 :(得分:0)
应该可以用Cream for Java来解决问题。还有一个适用于C#的版本CSharpCream。
答案 9 :(得分:0)
在个人项目中做了类似的事情,但是用php代码。 如果您想移植到C#,请放心。
此代码考虑了多个组合相同的可能性,因此返回值将是x
个最佳结果的数组。
注意:这是考虑到任何一项在每个结果中可以使用0或1次
<?php
$products = [
['id' => 1, 'price' => 3.00, 'energy' => 200],
['id' => 2, 'price' => 14.10, 'energy' => 3200],
['id' => 3, 'price' => 2.66, 'energy' => 300],
['id' => 4, 'price' => 5.00, 'energy' => 450],
['id' => 5, 'price' => 6.23, 'energy' => 667],
['id' => 6, 'price' => 7.00, 'energy' => 1200]
];
function genCombinations($values, $count = 0)
{
// Figure out how many combinations are possible:
$comboCount = pow(count($values) , $count);
$r = [];
// Iterate and add to array
for ($i = 0; $i < $comboCount; $i++){
$r[] = getCombination($values, $count, $i);
}
return $r;
}
// State-based way of generating combinations:
function getCombination($values, $count, $index)
{
$result = [];
for ($i = 0; $i < $count; $i++) {
// Figure out where in the array to start from, given the external state and the internal loop state
$pos = $index % count($values);
// Append and continue
$result[] = $values[$pos];
$index = ($index - $pos) / count($values);
}
return $result;
}
//maximize energy for given price
function getBestProductCombinations($products,$price_limit){
//find all combinations where each product is either selected or not - true or false
$combos = genCombinations([true,false],count($products));
$results = [];
foreach($combos as $combo){
//loop through each combination and get a result
$sum_price = 0;$items = [];$sum_energy = 0;
foreach($combo as $i => $o){
//loop through the array of true/false values determining if an item is on or off
if($o){
//if on, add item to result
$sum_price += $products[$i]['price'];
$sum_energy += $products[$i]['energy'];
$items[] = $products[$i];
}
}
if($sum_price <= $price_limit){
//if sum of result is within the price limit, add to the results array
$results[] = [
'items' => $items,
'price' => $sum_price,
'energy' => $sum_energy
];
}
}
$best = $results[0];$ra = [$best];
foreach($results as $k => $result){
if($k === 0){continue;}//skip first iteration as it was set above
//check if the energy is higher than the best, or if equal, check if the price is better
if($result['energy'] > $best['energy'] || ($result['energy'] === $best['energy'] && $result['price'] < $best['price'])){
//reset best to the current result, reset return array
$best = $result;
$ra = [$best];
}else if($result['energy'] === $best['energy']){
//current result is the same as best, add it to the return array
$ra[] = $result;
}
}
return $ra;
}
echo '<pre>'.json_encode(getBestProductCombinations($products,10),JSON_PRETTY_PRINT).'</pre>';
那会给你的:
[
{
"items": [
{
"id": 3,
"price": 2.66,
"energy": 300
},
{
"id": 6,
"price": 7,
"energy": 1200
}
],
"price": 9.66,
"energy": 1500
}
]