P2089 烤鸡

该代码利用深度优先搜索(DFS)策略,寻找在限定条件下(总美味程度等于给定值n且配料不超过10种)的所有可能的美食配料组合。程序定义了一个二维数组存储结果,并通过递归函数进行遍历。当满足条件时,将组合存入结果数组中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10005;
int n, k, m;
int a[maxn][15];

int ans[15];
int num = 0;
void dfs(int sum, int x) // 总美味程度,已经选好了的配料种数
{
   if (sum > n)
   {
      return;
   }
   else if (sum == n && x > 10)//符合条件
   {
      for (int i = 1; i <= 10; i++)
      {
         a[num][i] = ans[i];
      }

      num++;
      return;
   }
   else if (sum != n && x > 10)
   {
      return;
   }

   ans[x] = 1;
   dfs(sum + 1, x + 1);//sum+1/2/3,位置右移

   ans[x] = 2;
   dfs(sum + 2, x + 1);

   ans[x] = 3;
   dfs(sum + 3, x + 1);
}
int main()
{
   cin >> n;
   if (n < 10 || n > 30)
   {
      cout << 0;
      return 0;
   }
   dfs(0, 1);
   cout << num<<endl;
   for (int j = 0; j < num; j++)
   {
      for (int i = 1; i <= 10; i++)
      {
         cout<<a[j][i]<<" ";
      }
      cout<<endl;
   }
}

<think>好的,我现在需要解决用户关于洛谷P2089烤鸡问题的Java实现请求。首先,我要明确题目要求。根据引用[2],题目描述是:Hanke有10种配料,每种可以放1到3克,烤鸡的美味程度为所有配料质量之和。输入一个n,表示总质量,输出所有可能的配料组合。如果n不在10到30之间,则输出0。否则,输出方案数,接着是所有可能的组合。 接下来,我需要考虑如何用Java实现这个问题。常见的解法是枚举所有可能的组合,因为每种配料有3种可能(1、2、3克),总共有3^10种情况。但3^10等于59049,这在计算上是可行的,所以直接暴力枚举是可行的。 首先,我需要生成所有可能的10个数的组合,每个数在1到3之间。然后计算它们的和是否等于n。如果等于,记录下来。最后输出结果。 可能的实现步骤: 1. 检查输入n是否在10到30之间,否则输出0。 2. 生成所有可能的组合,可以用递归或循环嵌套。但因为10层循环不现实,递归更合适。 3. 使用回溯法生成组合,逐个位置尝试1、2、3,并累加当前总和,当组合填满10个时检查总和是否等于n。 4. 收集所有符合条件的组合,最后输出数量和具体组合。 另外,引用[1]中提到两种解法,直接枚举和剪枝优化。这里可能需要考虑剪枝,比如在生成过程中如果当前总和已经超过了n或者剩下的位置即使全填1也无法达到n,可以提前终止,减少递归次数。 例如,在递归过程中,当前已经选择了k种配料,总和为sum,剩下的(10 - k)种至少需要(10 - k)*1克,所以如果sum + (10 - k) > n,或者sum + (10 - k)*3 < n,就可以剪枝。 这样能有效减少不必要的递归调用,提升效率。 现在考虑Java代码结构。主函数读取输入n,判断范围。然后初始化结果列表,进行回溯搜索。最后输出结果。 可能的代码结构: - 使用一个ArrayList来存储所有符合条件的组合,每个组合用int数组或字符串表示。 - 递归函数参数包括当前配料位置、当前总和、当前组合数组。 - 剪枝条件在递归前判断,提前终止无效路径。 然后测试样例,比如输入11,应该输出10种组合,每个组合有10个数,每个数1或2,其中总和为11。 需要注意输出顺序,题目中的样例输出是按字典序排列的,所以递归中要按照顺序生成1、2、3,这样自然保持字典序。 最后,处理输出格式,先输出方案数,然后每行一个组合,数字用空格分隔。 现在编写代码时要注意效率,虽然数据量不大,但剪枝能优化时间。同时,Java中字符串拼接可能影响性能,但这里数据量小,可以接受。 可能的代码实现: 使用回溯法,逐层填充每个位置的1、2、3,并维护当前总和,当填充到第10层时检查总和是否等于n。符合条件的存入列表。 剪枝条件:在每一步,如果当前总和加上剩余位置的最小可能(全1)超过n,或者当前总和加上剩余位置最大可能(全3)小于n,就停止递归。 例如,当前在第k步,已经用了k个配料,总和为sum。剩下的10 - k个配料,最小总和是(10 - k)*1,最大是(10 - k)*3。如果sum + (10 -k)*1 >n 或者 sum + (10 -k)*3 <n,则不可能,剪枝。 这样可以减少递归次数。 现在编写Java代码: 主类读取n,检查范围,初始化结果列表,调用回溯方法,输出结果。 回溯方法的参数:当前步骤step(0到9),当前总和currentSum,当前数组current。 每次递归,循环i从1到3,设置current[step] =i,计算新的总和,检查是否剪枝,否则继续递归下一层step+1。 当step ==10时,检查currentSum是否等于n,是的话添加到结果列表。 这样实现即可。 然后处理输出,先输出结果数量,然后遍历列表输出每个组合。 测试案例: 输入11,输出应该是10种组合,每种组合总和为11,每个位置是1或2,且恰好有一个位置是2,其余是1。 例如,第一个组合是1 1 1 1 1 1 1 1 1 2,第二个是1 1 1 1 1 1 1 1 2 1,依此类推,共10种。 这样代码应该能正确生成这些组合。 最后,注意Java中数组的操作,使用Arrays.toString或者手动拼接字符串,但需要替换掉逗号为空格。 例如,将数组转为字符串,去掉逗号和括号,用空格分隔。 或者,在生成时用StringBuilder拼接每个数字加空格,最后trim掉末尾空格。 这样处理输出格式。</think>### P2089 烤鸡问题 Java 实现 #### 解法思路 本题要求枚举10种配料(每种1-3克)的所有可能组合,使得总质量等于输入值$n$。采用**回溯剪枝法**实现,在递归过程中通过以下优化提升效率: 1. **剪枝条件**:当当前总和超过$n$,或剩余配料无法达到$n$时提前终止递归 2. **字典序输出**:按自然顺序生成组合(1→2→3),保证结果直接有序 #### 完整代码 ```java import java.util.ArrayList; import java.util.Scanner; public class P2089 { static ArrayList<int[]> result = new ArrayList<>(); public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); if (n < 10 || n > 30) { System.out.println(0); return; } backtrack(new int[10], 0, 0, n); System.out.println(result.size()); for (int[] arr : result) { StringBuilder sb = new StringBuilder(); for (int num : arr) { sb.append(num).append(" "); } System.out.println(sb.toString().trim()); } } static void backtrack(int[] current, int step, int sum, int target) { if (step == 10) { if (sum == target) { result.add(current.clone()); } return; } for (int i = 1; i <= 3; i++) { int newSum = sum + i; int remainingSteps = 10 - step - 1; // 剪枝:后续步骤最小值/最大值是否可能满足条件 if (newSum + remainingSteps * 1 > target) break; if (newSum + remainingSteps * 3 < target) continue; current[step] = i; backtrack(current, step + 1, newSum, target); } } } ``` #### 代码解析 1. **输入校验**:直接排除$n<10$或$n>30$的无效情况 2. **回溯函数**: - `current`记录当前配料组合 - `step`表示当前处理到第几种配料 - `sum`为当前总质量 - 循环尝试1-3克,通过剪枝条件跳过无效分支[^1] 3. **结果输出**:使用`StringBuilder`优化字符串拼接效率 #### 测试样例 输入: ``` 11 ``` 输出: ``` 10 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 2 1 ... 2 1 1 1 1 1 1 1 1 1 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值