[ dfs ] 2. 烹饪料理

107 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

每日刷题 2021.04.16

题目

  • 欢迎各位勇者来到力扣城,城内设有烹饪锅供勇者制作料理,为自己恢复状态。
  • 勇者背包内共有编号为 0 ~ 4 的五种食材,其中 materials[j] 表示第 j 种食材的数量。通过这些食材可以制作若干料理,cookbooks[i][j] 表示制作第 i 种料理需要第 j 种食材的数量,而 attribute[i] = [x,y] 表示第 i 道料理的美味度 x 和饱腹感 y
  • 在饱腹感不小于 limit 的情况下,请返回勇者可获得的最大美味度。如果无法满足饱腹感要求,则返回 -1
  • 注意:
    • 每种料理只能制作一次

示例

  • 示例1
输入:`materials = [3,2,4,1,2]`
`cookbooks = [[1,1,0,1,2],[2,1,4,0,0],[3,2,4,1,0]]`
`attribute = [[3,2],[2,4],[7,6]]`
`limit = 5`

输出:`7`
解释:
食材数量可以满足以下两种方案:
方案一:制作料理 0 和料理 1,可获得饱腹感 2+4、美味度 3+2
方案二:仅制作料理 2, 可饱腹感为 6、美味度为 7
因此在满足饱腹感的要求下,可获得最高美味度 7
  • 示例2
输入:`materials = [10,10,10,10,10]`
`cookbooks = [[1,1,1,1,1],[3,3,3,3,3],[10,10,10,10,10]]`
`attribute = [[5,5],[6,6],[10,10]]`
`limit = 1`

输出:`11`
解释:通过制作料理 01,可满足饱腹感,并获得最高美味度 1

提示

  • materials.length == 5
  • 1 <= cookbooks.length == attribute.length <= 8
  • cookbooks[i].length == 5
  • attribute[i].length == 2
  • 0 <= materials[i], cookbooks[i][j], attribute[i][j] <= 20
  • 1 <= limit <= 100

解题思路

题意

  • 给你每个食材的个数,记为materials数组;给你一个菜谱cookbooks,上面记录了cookbooks.length个食谱,每个食谱都提供了其需要哪些食材;对应的每个食谱都存在一个相对应的美味值和饱腹值
  • 现在问你,如何在满足饱腹值的情况下,使美味值最大。需要注意的情况:如何不能满足饱腹值,就返回-1

思想

  • 常规的分析:对于每一个食谱来说,均可以与任意的一个食谱进行匹配组合,并且这个组合不一定是2个或者3个,因此不能使用二分查找和双指针来进行查找。
  • 从而就想到了使用dfs来实现,对于递归的调用,那么我们可以遍历每一个节点:选择和不选择的多重组合,从而来覆盖所有的情况,找出满足饱腹感后,最大的美味值。
  • 三步走dfs分析
    • 第一步:确定返回值和参数。void返回值,参数=>当前食谱下标,美味值,饱腹值
    • 第二步:确定终止条件。 当前食谱的下标 == len,说明已经遍历过了最后一个食谱了,没有可以进行遍历的食谱了,就返回。
    • 第三步:确定单层的循环逻辑。1.不选择当前的食谱 2.选择当前的食谱(选择的话,需要先写上选择当前食谱需要执行的操作,再进行dfs下一个状态)记得:最后返回到当前层的时候,一定要将状态还原回去,不要影响下一次操作。

AC代码

var perfectMenu = function(materials, cookbooks, attribute, limit) {
  // 参数:食谱,做还是不做
  let len = cookbooks.length;
  let book = cookbooks,me = materials,att = attribute;
  let max = -1;
  function dfs(cur, pertty, lim) {
    if (cur >= len){
      if(lim >= limit){
        max = max < pertty ? pertty : max;
      }
      return;
    }
    // 不做当前的料理
    dfs(cur + 1, pertty, lim);
    // 做当前的料理
    // 书写选择的逻辑
    // 判断是否所有的食材都存在
    let lenB = book[cur].length;
    // console.log('BBB', lenB)
    let flag = true;
    for(let i = 0; i < lenB; i++) {
      if(me[i] < book[cur][i]) {
        flag = false;
        break; 
      }
    }
    if(flag){
      for(let i = 0; i < lenB; i++) {
        me[i] = me[i] - book[cur][i];
      }
      // 如果食材都齐全,就计算饱腹值和美味值
      dfs(cur + 1, pertty + att[cur][0], lim + att[cur][1])
      for(let i = 0; i < lenB; i++) {
        me[i] = me[i] + book[cur][i];
      }
    }
  }
  // 美味值
  dfs(0, 0, 0)
  return max;
};

总结

  • 今天很开心,自己能够完整的写出来这个题目解法,并且在思路上还是实现上,都有了进一步的了解和分析。