【LeetCode每日一题】——LCP 51.烹饪料理

打印 上一主题 下一主题

主题 1786|帖子 1786|积分 5358

一【题目种别】



  • 回溯
二【题目难度】



  • 简单
三【题目编号】



  • LCP 51.烹饪料理
四【题目形貌】



  • 接待各位勇者来到力扣城,城内设有烹饪锅供勇者制作料理,为自己恢复状态。
  • 勇者背包内共有编号为 0 ~ 4 的五种食材,此中 materials[j] 表现第 j 种食材的数目。通过这些食材可以制作多少料理,cookbooks[j] 表现制作第 i 种料理需要第 j 种食材的数目,而 attribute = [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
    • 解释:通过制作料理 0 和 1,可满足饱腹感,并得到最高美味度 11

六【题目提示】



  • materials.length == 5
  • 1 <= cookbooks.length == attribute.length <= 8
  • cookbooks.length == 5
  • attribute.length == 2
  • 0 <= materials, cookbooks[j], attribute[j] <= 20
  • 1 <= limit <= 100
七【解题思绪】



  • 该题是回溯算法的经典应用,其实我以为挺好理解,符合人的根本直觉,主要是要把题目读懂
  • 既然是回溯,我们就要确定何时结束递归,根据题目形貌:“如果总饱腹感 >= 限定值,更新最大美味度”,以是这就是递归退出的条件,最后我们需要返回“最大美味度”
  • 那么核心递归过程呢?其实也很简单

    • 我们遍历每一道菜,对于每道菜我们起首需要检查这道菜是否已经做过了,如果做过了就跳过,否则继续下面的操纵(题目要求每道菜只能做一次)
    • 然后再检查当前剩的食材的数目还能否支持做完这道菜,如果不能那就结束,回到上一个状态,否则继续下面的操纵
    • 如果当前这道菜通过了所有检查,那么需要开始举行回溯操纵

      • 标志这道菜已经做了
      • 继续做别的菜,并更新美味度和饱腹感
      • 回溯,恢复材料,并标志这道菜还未做


  • 可以发现,以上整个过程就是回溯算法的标准模板,只不过根据题目要求添加了一些检查而已
  • 最后返回回溯盘算得到的“最大美味度”即可,具体细节可以参考下面的代码
八【时间频度】



  • 时间复杂度:                                        O                            (                            n                            m                                       2                               n                                      )                                  O(nm2^n)                     O(nm2n),                                        n                                  n                     n为菜品个数,                                        m                                  m                     m为材料的数目
  • 空间复杂度:                                        O                            (                            n                            )                                  O(n)                     O(n),                                        n                                  n                     n为菜品个数
九【代码实现】


  • Java语言版
  1. class Solution {
  2.     // 初始化最大美味度为 -1(表示无法满足饱腹感条件时返回 -1)
  3.     int maxRes = -1;
  4.     public int perfectMenu(int[] materials, int[][] cookbooks, int[][] attribute, int limit) {
  5.         // 记录每道菜是否做过
  6.         boolean[] exists = new boolean[cookbooks.length];
  7.         // 进行深度优先搜索
  8.         dfs(materials, cookbooks, attribute, limit, exists, 0, 0);
  9.         // 返回最大美味度
  10.         return maxRes;
  11.     }
  12.     public void dfs(int[] materials, int[][] cookbooks, int[][] attribute, int limit, boolean[] exists, int sumx, int sumy) {
  13.         // 如果总饱腹感 >= 限制值,更新最大美味度
  14.         if (sumy >= limit) {
  15.             maxRes = Math.max(sumx, maxRes);
  16.         }
  17.         // 获取菜谱总数
  18.         int len = cookbooks.length;
  19.         // 遍历每一道菜
  20.         for (int i = 0; i < len; i++) {
  21.             // 如果当前菜已经做过了,跳过
  22.             if (exists[i]) {
  23.                 continue;
  24.             }
  25.             // 检查当前所剩的材料是否足够制作第 i 道料理
  26.             int[] need = cookbooks[i];
  27.             boolean canMake = true;
  28.             for (int j = 0; j < need.length; j++) {
  29.                 if (materials[j] < need[j]) {
  30.                     canMake = false;
  31.                     break;
  32.                 }
  33.             }
  34.             // 可以制作这道菜
  35.             if (canMake) {
  36.                 // 标记当前菜已经制作
  37.                 exists[i] = true;
  38.                 for (int j = 0; j < need.length; j++) {
  39.                     materials[j] -= need[j];
  40.                 }
  41.                 // 递归调用,继续制作其它菜,并更新美味度和饱腹感
  42.                 dfs(materials, cookbooks, attribute, limit, exists, sumx + attribute[i][0], sumy + attribute[i][1]);
  43.                 // 回溯:恢复材料,并标记这道菜为未制作
  44.                 for (int j = 0; j < need.length; j++) {
  45.                     materials[j] += need[j];
  46.                 }
  47.                 exists[i] = false;
  48.             }
  49.         }
  50.     }
  51. }
复制代码

  • Python语言版
  1. class Solution:
  2.     def __init__(self):
  3.         # 初始化最大美味度为 -1(表示无法满足饱腹感条件时返回 -1)
  4.         self.maxRes = -1
  5.     def perfectMenu(self, materials: List[int], cookbooks: List[List[int]], attribute: List[List[int]], limit: int) -> int:
  6.         # 记录每道菜是否做过
  7.         exists = [False] * len(cookbooks)
  8.         # 进行深度优先搜索
  9.         self.dfs(materials, cookbooks, attribute, limit, exists, 0, 0)
  10.         # 返回最大美味度
  11.         return self.maxRes
  12.     def dfs(self, materials, cookbooks, attribute, limit, exists, sumx, sumy):
  13.         """
  14.         深度优先搜索函数
  15.         :param materials: List[int] 当前剩余的材料数量
  16.         :param cookbooks: List[List[int]] 每道菜需要的材料数量
  17.         :param attribute: List[List[int]] 每道菜的美味度和饱腹感
  18.         :param limit: int 最小饱腹感限制
  19.         :param exists: List[bool] 当前的菜是否已经制作
  20.         :param sumx: int 当前总美味度
  21.         :param sumy: int 当前总饱腹感
  22.         """
  23.         # 如果总饱腹感 >= 限制值,更新最大美味度
  24.         if sumy >= limit:
  25.             self.maxRes = max(self.maxRes, sumx)
  26.         # 获取菜谱总数
  27.         len_cookbooks = len(cookbooks)
  28.         # 遍历每一道菜
  29.         for i in range(len_cookbooks):
  30.             # 如果当前菜已经做过了,跳过
  31.             if exists[i]:
  32.                 continue
  33.             # 检查当前所剩的材料是否足够制作第 i 道料理
  34.             need = cookbooks[i]
  35.             can_make = True
  36.             for j in range(len(need)):
  37.                 if materials[j] < need[j]:
  38.                     can_make = False
  39.                     break
  40.             # 可以制作这道菜
  41.             if can_make:
  42.                 # 标记当前菜已经制作
  43.                 exists[i] = True
  44.                 # 减去所需的材料
  45.                 for j in range(len(need)):
  46.                     materials[j] -= need[j]
  47.                 # 递归调用,继续制作其它菜,并更新美味度和饱腹感
  48.                 self.dfs(materials, cookbooks, attribute, limit, exists, sumx + attribute[i][0], sumy + attribute[i][1])
  49.                 # 回溯:恢复材料,并标记这道菜为未制作
  50.                 for j in range(len(need)):
  51.                     materials[j] += need[j]
  52.                 exists[i] = False
复制代码

  • C语言版
  1. // 初始化最大美味度为 -1(表示无法满足饱腹感条件时返回 -1)
  2. int maxRes = -1;
  3. void dfs(int * materials, int materialsSize, int** cookbooks, int cookbooksSize, int** attribute, int limit, bool* exists, int sumx, int sumy)
  4. {
  5.     // 如果总饱腹感 >= 限制值,更新最大美味度
  6.     if (sumy >= limit)
  7.     {
  8.         if (sumx > maxRes) {
  9.             maxRes = sumx;
  10.         }
  11.     }
  12.     // 遍历每一道菜
  13.     for (int i = 0; i < cookbooksSize; i++)
  14.     {
  15.         // 如果当前菜已经做过了,跳过
  16.         if (exists[i])
  17.         {
  18.             continue;
  19.         }
  20.         // 检查当前所剩的材料是否足够制作第 i 道料理
  21.         bool canMake = true;
  22.         for (int j = 0;j < materialsSize; j++)
  23.         {
  24.             if (materials[j] < cookbooks[i][j])
  25.             {
  26.                 canMake = false;
  27.                 break;
  28.             }
  29.         }
  30.         // 可以制作这道菜
  31.         if (canMake)
  32.         {
  33.             // 标记当前菜已经制作
  34.             exists[i] = true;
  35.             for (int j = 0; j < materialsSize; j++)
  36.             {
  37.                 materials[j] -= cookbooks[i][j];
  38.             }
  39.             // 递归调用,继续制作其它菜,并更新美味度和饱腹感
  40.             dfs(materials, materialsSize, cookbooks, cookbooksSize, attribute, limit, exists, sumx + attribute[i][0], sumy + attribute[i][1]);
  41.             // 回溯:恢复材料,并标记这道菜为未制作
  42.             for (int j = 0; j < materialsSize; j++)
  43.             {
  44.                 materials[j] += cookbooks[i][j];
  45.             }
  46.             exists[i] = false;
  47.         }
  48.     }
  49. }
  50. int perfectMenu(int* materials, int materialsSize, int** cookbooks, int cookbooksSize, int* cookbooksColSize, int** attribute, int attributeSize, int* attributeColSize, int limit)
  51. {
  52.     // 初始化最大美味度为 -1(表示无法满足饱腹感条件时返回 -1)
  53.     maxRes = -1;
  54.     // 记录每道菜是否做过
  55.     bool* exists = (bool*)malloc(cookbooksSize * sizeof(bool));
  56.     for (int i = 0; i < cookbooksSize; i++) {
  57.         exists[i] = false;
  58.     }
  59.     // 进行深度优先搜索
  60.     dfs(materials, materialsSize, cookbooks, cookbooksSize, attribute, limit, exists, 0, 0);
  61.     // 释放资源
  62.     free(exists);
  63.     // 返回最大美味度
  64.     return maxRes;
  65. }
复制代码
十【提交结果】


  • Java语言版

  • Python语言版

  • C语言版


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

商道如狼道

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表