使用ruby中的成分和配方转换优化药剂酿造程序?

使用ruby中的成分和配方转换优化药剂酿造程序?,ruby,computer-science,Ruby,Computer Science,以下是我正在解决的问题: “哈姆雷特的三个女巫可以酿造任何药剂,只要她们有 正确的成分。假设五种成分是必需的 制作健康药水:蝾螈之眼(eon),青蛙之趾(tof),羊毛 蝙蝠(沃布),蝮蛇叉(af),狼牙(拖)。四种反应 在这些成分之间可以>发生: 4 eon+2 wob=3 af+4牵引力 3拖+1 tof=2 eon 1钻压+2 af=1飞行时间 4 tof+7拖+2 af=1健康药水 假设你能控制反应的顺序,写一个程序 可以计算出一个人可以用一个 给定成分的数量。下面是示例输出:如果我有3

以下是我正在解决的问题:

“哈姆雷特的三个女巫可以酿造任何药剂,只要她们有 正确的成分。假设五种成分是必需的 制作健康药水:蝾螈之眼(eon),青蛙之趾(tof),羊毛 蝙蝠(沃布),蝮蛇叉(af),狼牙(拖)。四种反应 在这些成分之间可以>发生:

4 eon+2 wob=3 af+4牵引力
3拖+1 tof=2 eon
1钻压+2 af=1飞行时间
4 tof+7拖+2 af=1健康药水

假设你能控制反应的顺序,写一个程序 可以计算出一个人可以用一个 给定成分的数量。下面是示例输出:如果我有34个元素, 59华氏度,20华氏度,5华氏度,20华氏度,我能做七种药剂。”

摘自:奥菲尔·弗里德、吉迪恩·弗里德和大卫·格罗斯曼。 “使用Ruby的计算机科学编程基础”,iBooks

以下是我的解决方案:

ingredients = Hash.new
potion = 0

puts "Welcome to potion brewer! To make a health potion you must combine 4 TOF + 7 TOW + 2 AF. Let's get started.\n\n" 

puts "How many EON do you have?"

ingredients["EON"] = gets.to_i

puts "How many TOF do you have?" 

ingredients["TOF"] = gets.to_i

puts "How many WOB do you have?" 

ingredients["WOB"] = gets.to_i

puts "How many AF do you have?"

ingredients["AF"] = gets.to_i

puts "How many TOW do you have?" 

ingredients["TOW"] = gets.to_i


while (ingredients["EON"] >= 4 and ingredients["WOB"] >= 2)
    ingredients["AF"] += 3
    ingredients["TOW"] += 4
    ingredients["EON"] -= 4
    ingredients["WOB"] -= 2
    # ==/== DEBUG ==/== 
#    puts "4 EON and 2 WOB convereted into +3 AF and +4 TOW."
#    puts ingredients["EON"]
#    puts ingredients["WOB"]
end
while ((ingredients["TOF"]/4) < (ingredients["AF"]/2))
   ## puts "debug"
    if (ingredients["WOB"] >= 1 and ingredients["AF"] >= 2)
        ingredients["TOF"] += 1
        ingredients["WOB"] -= 1
        ingredients["AF"] -= 2
   #     puts "1 WOB and 2 AF converted to +1 TOF."
    else
    break
    end
end
while (ingredients["TOF"] >= 4 and ingredients["TOW"] >= 7 and ingredients["AF"] >= 2)
    potion += 1
    ingredients["TOF"] -= 4
    ingredients["TOW"] -= 7
    ingredients["AF"] -= 2
    # ==/== DEBUG ==/==
    #puts "Potion created.."
end


puts "\n\nMade #{potion} potion(s).\n\n" 

for name in ingredients.keys
puts "You have " + ingredients[name].to_s + " " + name + " left.\n"
end    
components=Hash.new
药水=0
放上“欢迎来到药水酿造厂!要制作健康药水,您必须结合4 TOF+7 TOW+2 AF。让我们开始吧。\n\n“
写上“你有多少人?”
成分[“EON”]=获得
写上“你有多少豆腐?”
配料[“TOF”]=获得
输入“你有多少钻压?”
成分[“WOB”]=获得
放入“您有多少AF?”
成分[“AF”]=gets.to_i
放上“你有多少拖车?”
成分[“拖”]=到达
而(成分[“EON”]>=4和成分[“WOB”]>=2)
成分[“AF”]+=3
成分[“拖”]+=4
成分[“EON”]-=4
成分[“WOB”]-=2
#==/==调试==/==
#将“4 EON和2 WOB转换为+3 AF和+4拖曳。”
#添加配料[“EON”]
#放入配料[“WOB”]
结束
而((成分[“TOF”]/4)<(成分[“AF”]/2))
##放入“调试”
如果(成分[“WOB”]>=1和成分[“AF”]>=2)
成分[“TOF”]+=1
成分[“WOB”]-=1
成分[“AF”]-=2
#将“1 WOB和2 AF转换为+1 TOF。”
其他的
打破
结束
结束
而(成分[“TOF”]>=4,成分[“TOW”]>=7,成分[“AF”]>=2)
药剂+=1
成分[“TOF”]-=4
成分[“拖”]-=7
成分[“AF”]-=2
#==/==调试==/==
#放置“药剂已创建…”
结束
放置“\n\n制作{potion}药剂。\n\n”
在components.keys中查找名称
将“You have”+配料[名称]。置于\u s+“+name+”左侧。\n
结束
无论如何,这是我能想出的解决问题的“最整洁”的方法。我想我正确地安排了转换,这样在制作药剂时就不会有任何低效。我从书中的例子中得到了预期的结果

有人能确认它看起来确实不错/我没有错过一些可以进一步最大化我的魔药的主要优化吗?我找不到第三次转换(1wob+2af=1tof)有什么关系

谢谢!

有趣的问题

所以让我们重新表述一下:目标是计算“健康”药剂,如果该药剂的任何成分缺失,找到其他可以用来制造缺失成分的药剂

这听起来是一个递归算法。 首先,让我们对“制造药剂”问题进行建模

假设e有一个药剂配方,一个包含所有必需成分的散列(带负值)和得到的Ingredent,正值

例如:

4 eon + 2 wob = 3 af + 4 tow
可以写成:

formulae={:eon=>-4,:wob=>-2,:af=>3,:tow=>4}
因此,计算公式将非常简单,如下所示:

def compute_formulae ingredients,formulae
   result=ingredients.clone
   formulae.each do |needed,amount|
     if ingredients[needed]<-amount
        puts "Missing #{needed}" # The is an ingredient missing, we should probably exit now
        return nil
     else
        result[needed]+=amount
     end
   end
   result
end

现在,有一些小细节,比如主循环(我们需要继续,只要我们能获得新的“运行状况”)、错误(何时停止在这个递归循环中)、输入部分,但我把它留给读者了!

我也发现这个问题很有趣

将问题建模为a可以保证获得最佳解决方案。图中的每个节点(顶点)表示每个剩余成分的数量列表,而每个边表示根据其中一个反应公式调整成分的数量

要查找具有最多健康药水的节点,请在图形上执行一个类似于(DFS)的操作

对于每个节点,如果没有足够的成分来执行任何反应,则返回所制药水的数量。否则,如果节点为非终端,则执行每个有效反应,并返回其中哪一个最终产生的药水最多

可以使用
memo
来避免重新评估节点,从而大大加快算法的速度

下面是一个使用递归作为隐式堆栈(用于执行DFS)的相关代码段:


请参阅,以获得一个可用但简单的版本。

非常感谢!我正在使用的书没有介绍其中的一些方法,但我肯定会开始查找它们以完成问题的解决。
formulas=[
 {:tof=>-4,:tow=>-7,:af=>-2,:health=>1},
 {:eon=>-4,:wob=>-2,:af=>3,:tow=>4},
 {:tow=>-3,:tof=>-1,:eon=>2},
 {:wob=>-1,:af =>-2,:tof=>1}
  ]
formulas.each{|f| f.default=0} # Just ensure that there is de fault value for all ingredients


def find_missing_ingredient ingredients,formulas,missing
   formulas.each do | formulae |
      if formulae[missing]>0
        compute_formulae_ingredient ingredients,formulae
      end
   end
end

# so basically, the problem is
ingredients={:eon=>34,:tof=>59,:wob=>20,:af=>5,:tow=>20}
ingredients.default=0

while find_missing_ingredient ingredients,formulas,:health
end
def max_potions(ingredients, memo={})

  # get all available reactions as a list
  reactions = get_reactions(ingredients)

  # if no reactions are possible, return 
  # the number of health potions made
  return ingredients[:hp] if reactions.empty?

  # try every possible reaction for this set 
  # of ingredients and determine the maxiumum
  maximum = 0

  reactions.each do |reaction|
    key = reaction.hash

    # retrieve this node's value if already visited
    if memo.include?(key)
      result = memo[key]
    else # calculate and save the node's value
      result = max_potions(reaction, memo)
      memo[key] = result
    end 

    # update the maximum as necessary
    maximum = result if result > maximum 
  end 

  return maximum
end