2011-10-21 31 views
1

我有以下問題。我想使用php & mysql來制定飲食計劃。 我有以下幾點:飲食計劃邏輯,匹配最佳結果

  • 麪包:蛋白質,碳水化合物的2G,脂肪
  • 4克1克糖:蛋白質,碳水化合物6克的克脂肪
  • 咖啡的3G:蛋白質8克,碳水化合物的2G,脂肪
  • 肉類2G:蛋白質,碳水化合物的0克,脂肪12克7克
  • 牛奶:蛋白質,碳水化合物12克,脂肪2克16g的

擁有以上,我想找到最好的組合,以匹配以下總數:

目標:160克蛋白質 - 41克碳水化合物 - 120克脂肪。

,並顯示類似結果:5個塊肉,3個牛奶等

我沒有用php mysql的&一個問題。我試圖找出這個問題背後的邏輯。

回答

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 

這將返回三個結果,每個結果都以不同的方式查看數據。

讓我知道它是否有效!

0

這個問題本身有點缺陷。你是否試圖儘可能接近這些目標而不必過度?你只是在尋找接近這些數字的「解決方案」嗎?根據你如何定義合格的答案,這可能是一個非常簡單或非常非常難以解決的問題。

例如,添加一種新的成分,每種蛋白質含1克,碳水化合物和脂肪。另外再添加3種成分,每種成分含有1克獨特的營養物質 - 一種是1克蛋白質,0碳水化合物/脂肪,一種是1克碳水化合物0克蛋白質/脂肪等。在這裏,您至少有兩種,即使不是很多,都會完全匹配目標。

讓我們繼續,並假設蛋白質食物對你來說很重要,所以你寧願有更多的1g/1g/1g營養素。如果我們不能完全達到目標,但是如果我們沒有喝15杯牛奶和其他東西,我們如何權衡解決方案。

揹包問題是一個很好的開始,但有一百萬種不同的方式可以將這個問題分解成若想要嘗試編碼解決方案,我建議嘗試解決某些具體問題然後嘗試擴展因爲你明白髮生了什麼。