回溯法解决P2089 烤鸡问题太香啦,组合问题就用回溯法就对了!

学回溯的第二天,发现之前做过的一道洛谷的枚举题也可以用回溯法去解决,还是相当滴nice的。

先来看看leetcode上的这两道题

216.组合总和III 

题目链接:216. 组合总和 III

思路就是比组合问题多了一个和为n的限制,大体还是可以按模板来的,代码如下:

代码:

class Solution {List<Integer> temp = new ArrayList<>();List<List<Integer>> result = new ArrayList<>();public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k, n, 1, 0);return result;}// 1. 参数分别是:k个数、和为n、起始下标值(保证组合元素不重复)、求和计数器public void backtracking(int k, int n, int startIndex, int sum) {// 2. 循环终止条件,当temp中元素达到K个时,说明要停止往下递归了if(temp.size() == k) {if(sum == n) {  // 如果和等于n,则收集结果result.add(new ArrayList<>(temp));return;}else {         // 如果不满足,那么什么都不干return;}}// 3. 单层循环逻辑for(int i = startIndex; i <= 9; i++) {  // 每次从传入的起始下标开始  sum += i;                           // 记录这一次的和if(sum > n){                        // 剪枝操作,如果和都大于n了,下面也就没有递归和加入集合temp集合的必要了return;}temp.add(i);                        // 满足条件的直接加入temp中backtracking(k, n, i + 1, sum);     // 递归sum -= i;                           // 回溯,计数器也要回溯temp.remove(temp.size() - 1);}}
}

P2089 烤鸡

题目链接:P2089 烤鸡

做完这道题,我就想起了洛谷的这道P2089 烤鸡问题,这道题,比216.组合总和III 还更简单,它就是当n等于输入的n,k=10的限制要求,所以很容易写出类似的回溯代码:

回溯法代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;public class Main {static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));static List<Integer> temp = new ArrayList<>();	static List<List<Integer>> result = new ArrayList<>();static int count = 0;		// 结果次数计数器public static void main(String[] args) throws IOException {in.nextToken();int n = (int) in.nval;backtracking(n,0);			// 调用递归(回溯)方法// 由于题目中说了,要先打印个数,再打印组合情况,所以要单独写个逻辑if(count > 0) {out.println(count);for(List<Integer> list : result) {for(int s : list) {out.print(s + " ");}out.println();}}else {out.println(count);}out.close();}private static void backtracking(int n, int sum) {if(temp.size() == 10) {if(sum == n) {count++;result.add(new ArrayList<>(temp));return;}else {return;}}for(int i = 1; i <= 3; i++) {sum += i;if(sum > n) {// 剪枝return;}temp.add(i);backtracking(n,sum);// 回溯sum -= i;temp.remove(temp.size() - 1);}}
}

可以看出来,和上面的216.组合总和III 问题没什么区别,就是多了一个题目要求的,需要先打印次数,再打印结果,但是这是洛谷上的题,还需要写Main函数,不能单单只写一个方法体,当然,下面还有一种这道题的解法,因为这道题只需要10个数字组合,并且数字只有1-3,所以可以直接10个for循环(类似于“百钱白鸡”问题的升级版),时间复杂度也只有O(3^10)而已,是个常数,可以AC的,下面是代码:

暴力枚举代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;public class Main {public static void main(String[] args) throws IOException {StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));in.nextToken();int count = 0;int n = (int) in.nval;if(n - 1 < 9 || n > 30) {out.print(0);}else {for(int a = 1; a <= 3; a++) {for(int b = 1; b <= 3; b++) {for(int c = 1; c <= 3; c++) {for(int d = 1; d <= 3; d++) {for(int e = 1; e <= 3; e++) {for(int f = 1; f <= 3; f++) {for(int g = 1; g <= 3; g++) {for(int h = 1; h <= 3; h++) {for(int i = 1; i <= 3; i++) {for(int j = 1; j <= 3; j++) {if(a + b + c + d + e + f + g + h + i + j == n) {count++;}}}}}}}}}}}out.println(count);for(int a = 1; a <= 3; a++) {for(int b = 1; b <= 3; b++) {for(int c = 1; c <= 3; c++) {for(int d = 1; d <= 3; d++) {for(int e = 1; e <= 3; e++) {for(int f = 1; f <= 3; f++) {for(int g = 1; g <= 3; g++) {for(int h = 1; h <= 3; h++) {for(int i = 1; i <= 3; i++) {for(int j = 1; j <= 3; j++) {if(a + b + c + d + e + f + g + h + i + j == n) {out.print(a + " ");out.print(b + " ");out.print(c + " ");out.print(d + " ");out.print(e + " ");out.print(f + " ");out.print(g + " ");out.print(h + " ");out.print(i + " ");out.println(j);}}}}}}}}}}}}out.close();}
}

看这代码也是相当的炸裂了,哈哈哈哈,但是可以AC,还比回溯法AC更快!

两种方法测试通过情况对比:

17.电话号码的字母组合

题目链接:17. 电话号码的字母组合

一开始也是没想到用哈希表的思想来映射每一个数字对应的字符串,所以导致最后没做出来,这题关键就在于用一个String数组,通过数组下标作为值,映射一个字符串作为键,即:

String[] table = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

然后回溯,就是以传入的字符串大小为抽象树的深度,下面是代码:

代码:

class Solution {List<String> result = new ArrayList<>();String[] table = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};public List<String> letterCombinations(String digits) {if(digits.isEmpty()) {return result;}StringBuilder str = new StringBuilder();backtracking(digits, 0, str);return result;}// 1. k表示深度,用StringBuilder类型来做拼接操作更方便private void backtracking(String digits, int k, StringBuilder str) {if(str.length() == digits.length()) {result.add(str.toString());return;}int number = digits.charAt(k) - '0';	// 获取digits对应的第k个数字的数值String numberStr = table[number];		// 根据数字,在表中找到相应数字(如,2对应的“abc”)for(char ch : numberStr.toCharArray()) {str.append(ch);backtracking(digits, k + 1, str);   // 注意这里层数参数时,不能传k++,因为k++会改变所有递归的k,// k只记录这一个分支的层数,所以直接加1// 回溯str.deleteCharAt(str.length() - 1);}}
}

这题还有一个关键,就是在调用递归时,深度的参数不能传k++,即使是回溯了,也不行,k是随着层数越往下越深,而不是所有的k。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/672622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式系统设计师

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 第一章 计算机系统基础1、数值转换数的转换数据的存储单位 第一章 计算机系统基础 1、数值转换 数的转换 数据的存储…

解决“使用Edge浏览器每次鼠标点击会出现一个黑色边框”的问题

目录 一 问题描述 二 解决方案 三 方案来源 四 参考资料 & AI工具 一 问题描述 为了方便进行收藏夹同步&#xff0c;开始从Chrome浏览器切换到Edge浏览器。在使用Edge浏览器过程中发现“每次鼠标点击会出现一个黑色边框”&#xff08;效果如下图所示&#xff09;&#…

去照片背景的方法有哪些?分享这些简单的方法给你

在忙碌的日常工作中&#xff0c;不少朋友经常需要整理大量的图片素材。有时候&#xff0c;我们需要将那些带有背景色的图片转换成透明素材&#xff0c;这样在其他场合使用起来会更加方便。那么&#xff0c;有没有一种简便的方法&#xff0c;能将图片的背景去掉&#xff0c;轻松…

重学Java 13.面向对象.1

在熟悉的事物中循环 ——24.2.7 一、static关键字 1.static关键字的介绍以及基本使用 1.概述&#xff1a;static是一个静态关键字 2.使用&#xff1a; a.修饰一个成员变量&#xff1a; static 数据类型 变量名 b.修饰一个方法&#xff1a; 修饰符 static 返回值类型 方法名&am…

【办公技巧】如何设置Word文档部分内容无法编辑?

工作中&#xff0c;我们可能会在word中制作一些请柬、表格之类的&#xff0c;有些文件内容不想要进行修改&#xff0c;为了防止他人随意修改内容。我们可以设置限制编辑&#xff0c;可以对一部分内容设置限制编辑&#xff0c;具体方法如下&#xff1a; 我们将需要将可以编辑的…

作业2.6

一、填空题 1、一个类的头文件如下所示&#xff0c;num初始化值为5&#xff0c;程序产生对象T&#xff0c;且修改num为10&#xff0c;并使用show()函数输出num的值10。 #include <iostream.h> class Test { private: static int num; public: Test(int); void sh…

【华为 ICT HCIA eNSP 习题汇总】——题目集13

1、以下在项目规划阶段中需要完成的工作是&#xff08;&#xff09;。 A、确定技术方案 B、了解项目背景 C、选择网络产品 D、规划 IP 地址 考点&#xff1a;网络规划与设计 解析&#xff1a;&#xff08;B&#xff09; 确定技术方案是在网络规划的设计阶段完成的工作&#xff…

#Z2322. 买保险

一.题目 二.思路 1.暴力 训练的时候&#xff0c;初看这道题&#xff0c;这不就打个暴力吗&#xff1f; 2.暴力代码 #include<bits/stdc.h> #define int long long using namespace std; int n,m,fa,x,y,vis[1000001],ans; vector<int> vec[1000001]; void dfs(i…

如何实现高效的Web自动化测试?

随着互联网的快速发展&#xff0c;Web应用程序的重要性也日益凸显。为了保证Web应用程序的质量和稳定性&#xff0c;Web自动化测试成为必不可少的一环。然而&#xff0c;如何实现高效的Web自动化测试却是一个值得探讨的课题。 首先&#xff0c;选择合适的测试工具是关键。市面…

Android 13.0 原生SystemUI下拉通知栏每条通知默认展开

1.前言 在13.0的系统rom原生开发中,在在对SystemUI下拉通知栏做定制的时候,在下拉状态栏的时候,通知栏中最后一条通知默认是收缩的 点击按钮 就会展开 原生系统systemui就是如此,为了更美观 所以要求最后一条通知也默认展开,显得更美观 最终效果图: 2.原生SystemUI下拉通…

THM学习笔记——枚举

复制以下内容时注意中英文符号区别 在枚举之前我们要将shell升级为完全交互式的tty。 这涉及以下几条命令 python -c import pty;pty.spawn("/bin/bash") stty raw -echo export TERMxterm rlwrap nc -lvnp 443 从以上选一条即可 手动枚举 以下命令只需了解即可&…

VS Code中主程序C文件引用了另一个.h头文件,编译时报错找不到函数

目录 一、问题描述二、问题原因三、解决方法四、扩展五、通过CMake进行配置 一、问题描述 VS Code中主程序C文件引用了另一个.h头文件&#xff0c;编译时报错找不到函数 主程序 main.c #include <stdio.h> #include "sumaa.h"int main(int, char**){printf(&q…

thinkphp获取用户最新的阅读记录,按书籍id去重,返回最新的阅读记录

通过uid查询data_user_zhangjie的记录 去重shuji_id 获取createtime最新的一条数据 //获取用户章节记录public function getUserZhangjieList(){$uid = input(uid);if(empty

机器学习 | 一文看懂SVM算法从原理到实现全解析

目录 初识SVM算法 SVM算法原理 SVM损失函数 SVM的核方法 数字识别器(实操) 初识SVM算法 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种经典的监督学习算法&#xff0c;用于解决二分类和多分类问题。其核心思想是通过在特征空间中找到一…

详述FlinkSql Join操作

FlinkSql 的 Join Flink 官网将其分为了 Joins 和 Window Joins两个大类&#xff0c;其中里面又分了很多 Join 方式 参考文档&#xff1a; Joins | Apache Flink Window JOIN | Apache Flink Joins 官网介绍共有6种方式&#xff1a; Regular Join&#xff1a;流与流的 Joi…

使用Softing edgeConnector模块将云轻松连接到Siemens PLC

一 工业边缘的连接解决方案 云服务提供商 (CSP) 引入了服务和功能&#xff0c;以简化基于云的工业物联网解决方案的实施。Azure Industrial IoT Platform或AWS IoT SiteWise支持标准协议和接口&#xff0c;例如OPC UA或MQTT。但是&#xff0c;如果您希望在典型的旧改项目中连接…

VM安装Centos7

目标&#xff1a; 一&#xff0c;安装Centos7 二&#xff0c;ssh可以连接 1 新建虚拟机 一直下一步 2 直到此处&#xff0c;选择稍后安装 一直下一步直到完成。 3 选中虚拟机&#xff0c;点击设置 选择CD/DVD&#xff0c;选取ISO映像文件。 4 等待安装 并且设置root密码 5…

Redis -- zset有序集合

聪明在于勤奋&#xff0c;天才在于积累。 目录 zset 有序集合 zset相关命令 zadd zcard zcount zrange zrevrange zrangebyscore zpopmax bzpopmax zpopmin bzpopmin zrank zscore zrem zRemRangeByRank zRemRangeByScore zincrby 集合间操作 zinte…

java日志框架总结(五、logback日志框架)

一、logback概述 Logback是由log4j创始人设计的又一个开源日志组件。 Logback当前分成三个模块&#xff1a; 1、logback-core, 2、logback- classic 3、logback-access。 1&#xff09;logback-core是其它两个模块的基础模块。 2&#xff09;logback-…

详解C++类和对象(中(类的6个默认成员函数))

文章目录 写在前面1. 类的6个默认成员函数2. 构造函数2.1 构造函数的引入2.1 构造函数的特性 3. 析构函数3.1 析构函数的引入3.2 析构函数的特性 4. 拷贝构造函数4.1 拷贝构造函数概念4.2 拷贝构造函数的特性4.3 拷贝构造函数典型调用场景 5. 赋值运算符重载5.1 运算符重载5.2 …