我有以下问题。我想用php& amp做一个饮食计划MySQL的。 我有以下内容:
有了上述内容,我想找到上述内容的最佳组合以匹配以下总数:
目标:160克蛋白质 - 41克碳水化合物 - 120克脂肪。
显示结果如:5块肉,3块牛奶等
我没有php和amp;的问题MySQL的。我试图找到这个问题背后的逻辑。
答案 0 :(得分:3)
不是微不足道的。获取有关Dynamic Programming的书籍或好网页,特别是Knapsack problem。
答案 1 :(得分:1)
这是一个应该有效的蛮力解决方案。这是一个SQL脚本(用SQL Server编写,应该在MySql中工作,但可能需要稍作修改),它会在找到最佳解决方案之前迭代所有可能的项目组合。
-- Limits by protein/carb/fat
DECLARE @protein_limit INT
SET @protein_limit = 160
DECLARE @carb_limit INT
SET @carb_limit = 90
DECLARE @fat_limit INT
SET @fat_limit = 120
-- Table holding valid items
DECLARE @items TABLE
(
id INT IDENTITY(1,1),
name VARCHAR(50),
protein INT,
carb INT,
fat INT
)
INSERT INTO @items
SELECT 'Bread', 1, 2, 4
UNION SELECT 'Sugar', 3, 6, 1
UNION SELECT 'Coffee', 8, 2, 2
UNION SELECT 'Meat', 7, 0, 12
UNION SELECT 'Milk', 16, 12, 2
DECLARE @item_count INT
SELECT @item_count = COUNT(*)
FROM @items
-- From: http://stackoverflow.com/questions/9507635/pivot-integer-bitwise-values-in-sql/9509598#9509598
DECLARE @bits TABLE
(
number INT,
[bit] INT,
value INT
)
; with AllTheNumbers as (
select cast (POWER(2, @item_count) as int) - 1 Number
union all
select Number - 1
from AllTheNumbers
where Number > 0
),
Bits as (
select @item_count - 1 Bit
union all
select Bit - 1
from Bits
where Bit > 0
)
INSERT INTO @bits (number, [bit], value)
select *, case when (Number & cast (POWER(2, Bit) as int)) != 0 then 1 else 0 end
from AllTheNumbers cross join Bits
order by Number, [Bit] desc
-- Table to hold trials - brute force!
DECLARE @trials TABLE
(
trial_id INT,
item_id INT,
item_quantity INT
)
DECLARE @trial_max INT
SET @trial_max = (@protein_limit + @carb_limit + @fat_limit) * (POWER(2, @item_count))
DECLARE @trial_id INT
SET @trial_id = 1
DECLARE @base_quantity INT
WHILE @trial_id <= @trial_max
BEGIN
SET @base_quantity = FLOOR((@trial_id / POWER(2, @item_count)))
INSERT INTO @trials (trial_id, item_id, item_quantity)
SELECT @trial_id + 1 + b.number
, id
, @base_quantity + b.value
FROM @items a
JOIN @bits b
ON a.id = b.[bit] + 1
--UPDATE @trials
--SET item_quantity = @base_quantity + (@trial_id % item_id)
--WHERE trial_id = @trial_id
SET @trial_id = @trial_id + POWER(2, @item_count)
END
-- Get results of each trial
SELECT *
FROM @trials a
JOIN @items b
ON a.item_id = b.id
ORDER BY a.trial_id
-- Use the trial_id field to reference the results of the previous select
SELECT *
FROM
(
SELECT trial_id
, SUM(protein * item_quantity) AS protein_total
, SUM(carb * item_quantity) AS carb_total
, SUM(fat * item_quantity) AS fat_total
FROM @trials a
JOIN @items b
ON a.item_id = b.id
GROUP BY trial_id
) a
WHERE protein_total <= @protein_limit
AND carb_total <= @carb_limit
AND fat_total <= @fat_limit
ORDER BY ((@protein_limit - protein_total) + (@carb_limit - carb_total) - (@fat_limit - fat_total)) ASC
-- This last query gets the best fit
SELECT c.name
, b.item_quantity
FROM
(
SELECT *
, ROW_NUMBER() OVER (ORDER BY ((@protein_limit - protein_total) + (@carb_limit - carb_total) - (@fat_limit - fat_total)) ASC) AS rn
FROM
(
SELECT trial_id
, SUM(protein * item_quantity) AS protein_total
, SUM(carb * item_quantity) AS carb_total
, SUM(fat * item_quantity) AS fat_total
FROM @trials a
JOIN @items b
ON a.item_id = b.id
GROUP BY trial_id
) a
WHERE protein_total <= @protein_limit
AND carb_total <= @carb_limit
AND fat_total <= @fat_limit
) a
JOIN @trials b
ON a.trial_id = b.trial_id
JOIN @items c
ON b.item_id = c.id
WHERE a.rn = 1
这将返回三个结果,每个结果都以不同的方式查看数据。
让我知道它是否有效!
答案 2 :(得分:0)
问题本身有点缺陷。您是否试图尽可能接近这些目标而不必过关?您是否只是在寻找与这些数字接近的“某种解决方案”?根据您如何定义哪些资格作为可接受的答案,这可能是一个非常容易或非常非常难以解决的问题。
例如,添加含有1g每种蛋白质,碳水化合物和脂肪的新成分。还要添加3种成分,每种成分含有1g独特的营养成分 - 一种是1g蛋白质,0种碳水化合物/脂肪,一种是1g碳水化合物0g蛋白质/脂肪等。这里你至少有两种,如果不是很多的解决方案,两者都会完全匹配目标。
让我们继续,并假设蛋白质食物对你很重要,所以你宁愿多吃1g / 1g / 1g营养素。如果我们不能完全达到目标,但是你没有喝15杯牛奶,那我们如何权衡解决方案。
背包问题是一个很好的开始,但有一百万种不同的方法可以解决这个问题,如果你打算尝试编写一个解决方案,我建议你尝试解决一些特定问题,然后尝试将其扩展为你了解幕后发生了什么。