深搜-选数类问题

news2024/11/25 19:51:32

目录

1.问题引入

2.知识讲解 

3.例题解析 

【例题1】全排列。

【例题2】素数环Ⅱ。 

【样例3】素数分解。 


1.问题引入

上一节探讨了迷宫类问题,和平时遇到的迷宫小游戏类似,可以使用搜索程序求得迷宫的路径和最短路。本小节继续研究深搜的另一类问题——选数类问题。

选数类问题在生活中也能经常遇到,比如数独游戏、八皇后摆放问题等等。因为这些难度较高,感兴趣的同学可以主动学习研究。

拓拓最近在研究简单的素数环问题,问题是这样的:从1、2、3、4、5、6这6个整数随机填写到下图所示的圆环内,要求任意相邻的圆圈内数字之和是素数。除了下图的方案,拓拓又找到了11种方案,你能找到另外的11种填写方案的画法吗?

2.知识讲解 

综合之前深搜的代码和框架,提取出新的代码框架如下:

全局状态变量

void dfs(当前状态)
{
  if(当前状态是目标状态)   // 判断
    进行相应处理(输出当前解、更新最优解、退出返回等)
  for(所有可行的新状态) {  // 扩展
    获取新状态;
    if(新状态没有访问过 && 需要访问 && 优化) {
      标记;
      dfs(新状态);
      取消标记;
    }
  }
}
int main()
{
  ...;
  dfs(初始状态);
  ...;
}

3.例题解析 

【例题1】全排列。

输入一个整数n(n≤9)。输出n的全排列。全排列是指从1~n这n个数中选取n个数的所有排列情况。

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

【问题分析】首先创建一个数组(盒子)存放排列的结果,逐个往该数组(盒子)中填放可能的数字,直到填的数字个数是n个。同时注意到不能选取之前选过的数字,所以采用数组标记的方式把选过的数字做个标记。

深搜的顺序如下:

① 向第一个盒子填一个数后向下搜索、向第二个盒子填第二个数向下搜索、向第三个盒子填第三个数后结束向下搜索并输出方案1 2 3;

② 回溯到上一层填完两个数的状态(没有其他方案)、继续回溯到上一层填完一个数的状态,发现有其他可能;

③ 填第二个数后向下搜索、填第三个数后结束向下搜索并输出方案1 3 2;

④ 回溯到填完两个数的状态、回溯到填完一个数的状态、回溯到没填数的状态;

⑤ 填第一个数(也就是填2数字)后向下搜索、填第二个数向下搜索、填第三个数后结束向下搜索并输出方案2 1 3;

⑥ 回溯到填完两个数的状态、回溯到填完一个数的状态,发现有其他可能;

。。。。。。

#include<bits/stdc++.h>
using namespace std;
int n;
int a[11];  //存放排列的结果
bool f[11];  //标记选过的数字
void dfs(int k) {  //向第k个盒子里填写数字
    if (k > n) {  //当k大于n时,说明n个盒子已经填好了
        for (int i = 1; i <= n; i++)
            cout << a[i] << " ";
        cout << endl;
        return;
    }
    for (int i = 1; i <= n; i++) {  //把所有的数字枚举一遍
        if (f[i] == 0) {  // i没有选过
            f[i] = 1;  //标记i已选择
            a[k] = i;  //把i放到k下标
            dfs(k + 1);  //递归填写k+1位置的数字
            f[i] = 0;  //取消标记
        }
    }
}
int main() {
    cin >> n;
    dfs(1); //开始向第一个盒子里面填数字
    return 0;
}

【例题2】素数环Ⅱ。 

从1~n(2≤n≤15)这n个数中随机摆成一个环,要求相邻的两个数的和是素数,按照由小到大请输出所有可能的摆放形式。

输入样例:

4

输出样例:

1:1 2 3 4
2:1 4 3 2
3:2 1 4 3
4:2 3 4 1
5:3 2 1 4
6:3 4 1 2
7:4 1 2 3
8:4 3 2 1
total:8

【问题分析】

素数环就是本节最开始引入的问题,现在我们可以用程序求解所有摆放的答案。下面分析是以样例输入的4举例。

环的形式不好处理,转变思路,可以把环从第一个要填的盒子和第4个要填的盒子剪开,那么就可以转化成一维数组存储。

如上图所示。填写数字时和全排列问题一样,但是本题多了一个条件,需要确保相邻两项的和是素数,因此在搜索的时候加上相邻两项之和是素数的判断。 

#include<bits/stdc++.h>
using namespace std;
int n, cnt;  //cnt是方案个数
int a[20];  //记录方案
bool f[20];  //标记i是否选过
bool prime(int x) {  //判断素数的标准代码
    if (x == 1) return 0;
    for (int i = 2; i <= sqrt(x); i++)
        if (x % i == 0) return 0;
    return 1;
}
void dfs(int k) {  //要填第k个数字
    if (k > n) {
        if (prime(a[1] + a[n])) {  //填完后,确保第1项和第n项之和也是素数
            cout << cnt++ << ":";
            for (int i = 1; i <= n; i++)
                cout << a[i] << " ";
            cout << endl;
        }
        return;
    }
    for (int i = 1; i <= n; i++) {
        //选择第k项填i时,要确保i与上一项a[k-1]的和是素数
        if (f[i] == 0 && ( k == 1 || prime(i + a[k - 1]))) {  
            f[i] = 1; //标记
            a[k] = i; //填写i
            dfs(k + 1); //递归填写k+1项
            f[i] = 0; //取消标记
        }
    }
}
int main() {
    cin >> n;
    dfs(1);
    cout << "total:" << cnt;
    return 0;
}

【样例3】素数分解。 

虽然素数不能分解成除1和其自身之外整数的乘积,但却可以分解成更多素数的和。你需要编程求出一个正整数n(10≤n≤200)最多能分解成多少个互不相同的素数的和。

例如,21 = 2 + 19是21的合法分解方法。21 = 2 + 3 + 5 + 11则是分解为最多素数的方法。所以21最多可以分解为4个不同素数的和。

【问题分析】当然你可以把所有分解方案都搜索出来,但实际上有更快的解法——在贪心的基础上搜索。

一个小小的贪心思路:尽可能选择更小的素数分解,这样得到的个数是最多的。证明也很简单,反证法:如果有某种方案中可以选择更大的素数分解,那么采用贪心策略用更小的素数替换掉更大的素数,分解的个数会更多(至少不会变少)。

因此我们第一次搜索得到的分解答案,就是分解的数字最多的分解方案。dfs的设计可以稍作调整,在dfs的过程中通过参数记录选到的数字、选了几个数、选的数字总和。

参考代码如下:

#include <bits/stdc++.h>
using namespace std;
int n, flag;
bool Prime(int x) {
    if (x < 2) return 0;
    for (int i = 2; i <= x / i; i++)
        if (x % i == 0) return 0;
    return 1;
}
// k:当前选到了哪个数
// cnt:已经选了几个数
// sum:已经选的数的总和
void dfs(int k, int cnt, int sum) {
    if (sum > n) return ;
    if (flag) return; //当有一种方案,就可以结束所有搜索
    if (sum == n) {
        cout << cnt;
        flag = 1;  //标记找到了分解方案
        return ;
    }
    for (int i = k; i <= n; i++) {  //每次从k开始选择素数,22行
        if (Prime(i)) {
            dfs(i + 1, cnt + 1, sum + i);  //24行
        }
    }
}
int main() {
    cin >> n;
    dfs(2, 0, 0);
    return 0;
}

说明:

(1) 注意理解dfs的参数,这里的k、cnt、sum都是当前的状态变量。

(2) 22行不需要从1循环到n,因为题目要求分解方案不能有相同的素数,因此之前的素数(无论选没选)不能再次选择了,这里也无需标记选择过的状态,每次从k往后找即可。

(3) 因为i满足是素数,而且因为(2)的原因也不会选择重复的素数,所以第24行就可以确定选择i。dfs(i + 1, cnt + 1, sum + i)的含义是:递归求解下一个数的选择,至少要从i+1开始选数;选择了i这个素数所以个数变成了cnt+1个,总和变成了sum+i。

(4) 一进入dfs的三个条件比较好理解,第一个if,当sum超过n时,分解方案是错误的,所以递归回到上一层选其他的数字;第二个if,当找到了一种方案,根据贪心的分析就得到了答案,此时就可以结束了所有的搜索;第三个if,第一次找到分解方案时,输出答案,标记结束所有的搜索。 

谢谢观看=关注我哦~

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

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

相关文章

MySQL数据库的认识及基础命令操作

目录 一、数据库的基本概念 1、数据库定义 &#xff08;1&#xff09; 数据 &#xff08;2&#xff09;表 &#xff08;3&#xff09; 数据库 2、 数据库管理系统&#xff08;DBMS&#xff09; 3、 数据库系统&#xff08;DBS&#xff09; 二、数据库系统发展史 1、 第一…

【RabbitMQ教程】第五章 —— RabbitMQ - 死信队列

&#x1f4a7; 【 R a b b i t M Q 教程】第五章—— R a b b i t M Q − 死信队列 \color{#FF1493}{【RabbitMQ教程】第五章 —— RabbitMQ - 死信队列} 【RabbitMQ教程】第五章——RabbitMQ−死信队列&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人…

SpringCloud:分布式事务Seata

1.什么是分布式事务 分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上&#xff0c;简单的说&#xff0c;就是一次大的操作由不同的小操作组成&#xff0c;这些小的操作分布在不同的服务器上&#xff0c;且属…

【Flutter】Flutter 创建每个页面公用的底部框

文章目录 一、 前言二、 创建公用底部框的步骤1. 创建一个公用的底部框 Widget2. 在页面中使用公用的底部框 Widget 三、 示例&#xff1a;电商应用中的公用底部框1. 创建电商应用的底部框 Widget2. 在电商应用的各个页面中使用底部框 Widget 四、 完整代码示例五、 一些注意事…

第一次ubuntu wsl ssh远程登录各种报错+解决

第一次ubuntu wsl ssh远程登录各种报错+解决 最新推荐文章于 2023-04-13 20:23:43 发布 kh3064 于 2020-11-03 15:12:16 发布 1869 收藏 5 文章标签: ubuntu

计算理论导引实验三:构造图灵机

计算理论导引实验三&#xff1a;构造图灵机 实验描述形式化定义图灵机M的状态图 算法设计与描述状态转移关系类键盘输入及逻辑处理类 编码实现测试运行 实验描述 要求构造一个能够识别语言L的图灵机。语言L的描述和实验内容如下图所示 形式化定义 根据实验描述&#xff0c;可…

【批量修改后缀名】如何批量去修改文件后缀名(亲测图文结合)

【写在前面】前段时间&#xff0c;因为素材需要&#xff0c;就去之前我制作相册的一个网站上下载了一批照片&#xff0c;但是照片下载下来的格式居然是.png!600*0&#xff0c;这种格式的也打不开&#xff0c;于是乎我自己就吭哧吭哧的去一个个的修改&#xff0c;然后我一想他娘…

EBU5476 Microprocessor System Design 知识点总结_5 GPIO

GPIO General Purpose Input Output, Memory-Mapped IO 把设备&#xff0c;控制等寄存器映射到内存里。好处就是访问设备方式和内存一样&#xff0c;也不用设计复杂的IO电路&#xff0c;便捷&#xff1b;缺点在于占用了内存空间。 Peripheral-Mapped IO IO有一块专门的存储…

Vue|单文件组件与脚手架安装

一、单文件组件1.1 介绍1.2 文件组成1.3 加深认知 二、脚手架安装2.1 什么是脚手架?2.2 使用镜像2.3 全局安装vue/cli2.4 创建并启动项目 一、单文件组件 1.1 介绍 [.vue]文件&#xff0c;称为单文件组件&#xff0c;是Vue.js自定义的一种文件格式&#xff0c;一个.vue文件就…

AST使用(二)

//在此之前&#xff0c;先了解下path和node/*path指的是路径 其常用的方法当前路径所对应的源代码 : path.toString判断path是什么type&#xff0c;使用path.isXXX 这个方法 : if(path.isStringLiteral()){}获取path的上一级路径 : let parent path.parentPath;获取path的子…

nginx的安装及代理和负载均衡设置

一、通过yum方式进行安装 官网参考地址&#xff1a;https://nginx.org/en/linux_packages.html#RHEL 1.1 安装好依赖 执行下面的命令安装 sudo yum install yum-utils1.2、 先配置好yum源 新建文件/etc/yum.repos.d/nginx.repo&#xff0c;文件内容&#xff1a; [nginx-s…

一个成熟的软件测试工程师应该具备那些“技能”

1、良好的沟通 相信大家都在网上看到过各种吐槽程序员不解风情的段子&#xff0c;开怀大笑之余深思&#xff0c;作为一个测试工程师又何尝不是如此&#xff1f;通常沟通技能成为横亘在测试工程师与其他合作部门之间的万丈鸿沟&#xff0c;也成为测试工程师成长的最大瓶颈。下面…

Vector-常用CAN工具 - 以太网报文收发方向

目录 Rx 和 Tx 标记 Example&#xff1a;从 CANoe 向 ECU 发送以太网数据包 用例 2&#xff1a;从 ECU 接收以太网数据包 如何仅显示物理或虚拟通信 如何仅显示 Rx 或 Tx 以太网数据包 VN5000以太网包过滤 1、什么是硬件过滤&#xff1f; 2、什么时候使用硬件过滤&…

useEffect,useLayoutEffect的基础知识和底层机制

useEffect 是 React 中一个重要的 Hook&#xff0c;用来处理组件的副作用操作。它的基础知识包括两个方面&#xff1a;执行时机和参数。 执行时机&#xff1a; useEff ect 的执行时机包括两种情况&#xff1a; 组件挂载时&#xff0c;即第一次渲染之后。组件更新时&#xff…

智能垃圾分类小程序,流量主变现,外卖cps权益变现,uniCloud云开发无需购买服务器和域名,助力每一位创业者。

技术优势 基于 uniapp uniCloud 研发&#xff0c;无需购买服务器和域名&#xff0c;uniCloud 是 DCloud 联合阿里云、腾讯云 serverless 构建。从此不用关心服务器运维、弹性扩容、大并发承载、防DDoS攻击等&#xff0c;轻松应对高并发应用&#xff0c; 传统小程序开通流量主…

Qt 多语言实现

简介 Qt Linguist 提供了一套加速应用程序翻译和国际化的工具。Qt 使用单一的源码树和单一的应用程序二进制包就可同时支持多个语言和书写系统。 使用 QTranslator 来加载生成的 qm 文件&#xff0c;就可以让程序显示指定的语言。 // 国际化翻译 QString language "CH…

项目Es、kafka、mysql容量评估方案和服务器资源预估方案

目录 1、Es 评估计划 一个接口jmeter压测qps 1万, logstash 读取日志文件写入es Logstash配置 Es容量变化前后差值/1万 * 1.67 * &#xff08;1副本数&#xff09; ~ 次接口es 容量 &#xff08;日志数据30kb&#xff09; 影响es存储的主要原因 通过 kibana 查看 堆栈》索…

管理类联考——英语——技巧篇——阅读理解

一、阅读理解A节选项的点 1.正确答案的五大特征 (1)“主题为王”原则&#xff1a;即正确答案通常与文章的中心思想、主旨大意有关。 (2)正确答案的特点&#xff1a;语言简化、反话正说、正话反说、关键词替换。 (3)正确答案要选相对的&#xff0c;不选绝对的。正确答案通常含有…

编译原理期末速成-LL(1)文法、FIRST集、FOLLOW集

文章目录 LL(1)文法的条件LL(1)分析法构造FIRST(α)构造FOLLOW(A)习题强化 LL(1)文法的条件 文法不含左递归 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。即若 对于文法中的每个非终结符A&#xff0c;若它存在某个候选首符集包含ε&#xff0c;则 这里&am…

面试被问到:测试计划和测试方案有什么区别?

面试的时候&#xff0c;很多小伙伴都被面试官问过这个问题 “测试计划和测试方案有什么区别”&#xff1f; 到底有什么区别呢&#xff1f;我们先好好了解下这两个文档。 一、测试计划 1、测试计划是什么&#xff1f; 测试计划是组织管理层面的文件&#xff0c;从组织管理的…