搜索剪枝

article/2025/9/16 2:23:44

目录

什么是剪枝

几种常见的剪枝

1.可行性剪枝

2.排除等效冗余

3.最优性剪枝

4.顺序剪枝

5.记忆化

运用实例

1.选数

2.吃奶酪

3.小木棍


什么是剪枝

剪枝:通过某种判断,避免一些不必要的遍历过程。搜索的时间复杂度通常很大,通过剪枝对搜索进行优化,可以大大提高程序运行的效率。

几种常见的剪枝

1.可行性剪枝

判断继续搜索是否能得到答案,如果不能,就返回

即:不可行,就返回

2.排除等效冗余

在搜索的几个分支中具有完全相同的效果时,选择其中一个走即可

即:有相同,选一个

3.最优性剪枝

和可行性剪枝有点相似,区别在于继续搜索可能得到答案,但一定不是最优

首先得到最优解:每搜索到一个解,和之前的解做对比,得到最优解

然后最优性剪枝:如果当前搜索到的解已经超过最优解,就返回

即:非最优,就返回

4.顺序剪枝

优化搜索顺序,更快得到解

即:先排序,再搜索

5.记忆化

记录每个状态的搜索结果,在后续搜索过程中检索这个状态,如果重复,就返回

即:有重复,就返回

运用实例

1.选数

(详见洛谷P1036):从n个整数中选k个整数相加,求和为素数共有多少种

输入:n,k,n个整数

输出:种类数

运用:可行性剪枝

#include<iostream>
#include<algorithm>
#include<cmath>
#define maxn 25
using namespace std;int a[maxn];
int ans = 0;
int n, k;bool isprime(int m)
{for (int i = 2; i <= sqrt(m); i++)if (m % i == 0) return false;return true;
}void dfs(int start,int count,int sum)//当前第start个数,当前已选数个数,当前已选数和
{if(count+n-start+1<k)//(可行性剪枝)当前已选数个数+剩余数个数<要选的总数个数k{return;}if (count == k){if(isprime(sum))ans++;return;//可行性剪枝}for(int i=start;i<=n;i++){dfs(i + 1, count + 1, sum + a[i]);}
}int main()
{cin >> n >> k;for (int i = 1; i <= n; i++){cin >> a[i];}dfs(1,0,0);cout << ans;
}

2.吃奶酪

(详见洛谷P1433):有n块奶酪,现在要把它们都吃掉,求最短的经过的距离(初始在原点处)

输入:奶酪数量n,每块奶酪的坐标

输出:最少距离(保留两位小数)

运用:可行性剪枝,最优性剪枝,记忆化剪枝

首先只加上可行性剪枝:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<iomanip>
#define maxn 20
using namespace std;double ans= 0x3f3f3f3f;
int n,visited[maxn];struct POINT{double x, y;
}a[maxn];double dis(POINT& a, POINT& b)
{return sqrt(pow((a.x - b.x), 2)*1.0 + pow((a.y - b.y), 2)*1.0);
}void dfs(int now,int count,double sum)//序号,吃掉数量,距离
{   if (count == n){ans = min(ans, sum);return;//不可行,返回}for (int i = 1; i <= n; i++){if (!visited[i]){visited[i] = 1;dfs(i, count+1, sum +dis(a[now],a[i]));visited[i] = 0;}}
}int main()
{cin >> n;for (int i = 1; i <= n; i++)cin >> a[i].x >> a[i].y;a[0].x = 0;a[0].y = 0;dfs(0,0,0);cout <<fixed<<setprecision(2) << ans;
}

只能得到50分

现在加上最优性剪枝:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<iomanip>
#define maxn 20
using namespace std;double ans= 0x3f3f3f3f;
int n,visited[maxn];struct POINT{double x, y;
}a[maxn];double dis(POINT& a, POINT& b)
{return sqrt(pow((a.x - b.x), 2)*1.0 + pow((a.y - b.y), 2)*1.0);
}void dfs(int now,int count,double sum)//序号,吃掉数量,距离
{if (sum >= ans)//最优性剪枝return;if (count == n){ans = min(ans, sum);return;}for (int i = 1; i <= n; i++){if (!visited[i]){visited[i] = 1;dfs(i, count+1, sum +dis(a[now],a[i]));visited[i] = 0;}}
}int main()
{cin >> n;for (int i = 1; i <= n; i++)cin >> a[i].x >> a[i].y;a[0].x = 0;a[0].y = 0;dfs(0,0,0);cout <<fixed<<setprecision(2) << ans;
}

 什么?竟然还不能通过

那就再加上记忆化剪枝,把每次计算的两点间距离都保存起来,下次遇到直接调用

#include<iostream>
#include<algorithm>
#include<cmath>
#include<iomanip>
#define maxn 20
using namespace std;double ans= 0x3f3f3f3f;
int n,visited[maxn];
double map[maxn][maxn];struct POINT{double x, y;
}a[maxn];double dis(POINT& a, POINT& b)
{return sqrt(pow((a.x - b.x), 2)*1.0 + pow((a.y - b.y), 2)*1.0);
}void dfs(int now,int count,double sum)//序号,吃掉数量,距离
{if (sum >= ans)//最优性剪枝return;if (count == n){ans = min(ans, sum);return;}for (int i = 1; i <= n; i++){if (!visited[i]){if (map[now][i])//记忆化,提取之前记录过的距离{visited[i] = 1;dfs(i, count + 1, sum + map[now][i]);visited[i] = 0;}else{map[now][i] = dis(a[now], a[i]);//记忆visited[i] = 1;dfs(i, count+1, sum +map[now][i]);visited[i] = 0;}}}
}int main()
{cin >> n;for (int i = 1; i <= n; i++)cin >> a[i].x >> a[i].y;a[0].x = 0;a[0].y = 0;dfs(0,0,0);cout <<fixed<<setprecision(2) << ans;
}

 恭喜,看来这道题不用dp是通过不了了的,然而我还不会dp,等以后再来解决吧

3.小木棍

(详见洛谷P1120):有一些同样长的木棍被随意砍成几段,求原始木棍的最小可能长度

输入:分段后的小木棍个数n,每个小木棍的长度

输出:最小可能的长度

运用:可行性剪枝,最优性剪枝,顺序剪枝

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;int n;
int a[110];int maxm = 0, minm = 51;//小木棍最长长度,最短长度
int ans;//当前成功拼接的木棍数
int p = 0;//木棍总长度void dfs(int x, int y, int z)//x:每根木棍期望长度,y:现在拼成长度,z:上一次使用的木棍长度
{if (ans * x == p){cout << x;exit(0);//(最优性剪枝)}for (int i = z; i >= minm; i--)//从最长的小木棍开始拼(顺序剪枝){if (a[i] && y + i <= x)//长度为a[i]的木棍拼接起来不会超过期望长度{y += i;a[i]--;if (y == x)ans++, y = 0;//拼接成功if (y == 0)dfs(x, y, maxm);//搜索下一个木棍elsedfs(x, y, i);//搜索下一个小木棍//回溯a[i]++;if (ans > 0 && y == 0)y = x - i,ans--;else y -= i;if (y == 0) break;//拼接没有成功,返回(可行性剪枝)if (y + i == x)break;//到达上一根木棍拼接状态,返回}}
}int main()
{cin >> n;for (int i = 1; i <= n; i++){int temp;cin >> temp;if (temp <= 50){	a[temp]++;//长度为temp的木棍数量+1p += temp;maxm = max(temp, maxm);minm = min(temp, minm);}}for (int i = maxm; i <= p / 2; i++)//小木棍木棍最长长度->总长度的一半{//木棍总长度也就是原始木棍长度一定能够整除单个木棍长度if(p%i==0){ ans = 0;dfs(i, 0, maxm);//期望长度=i,现在拼成长度=0,使用长度=maxm}}cout << p;//搜索不成功,全部拼成1根}


http://chatgpt.dhexx.cn/article/3KqSPoRQ.shtml

相关文章

【模型压缩】(二)—— 剪枝

一、概述 剪枝&#xff08;Pruning&#xff09;的一些概念&#xff1a; 当提及神经网络的"参数"时&#xff0c;大多数情况指的是网络的学习型参数&#xff0c;也就是权重矩阵weights和偏置bias&#xff1b;现代网络的参数量大概在百万至数十亿之间&#xff0c;因此…

环形队列的基本运算算法-数据结构教程

环形队列的基本概念 如图&#xff0c;其实它就是一个队列&#xff0c;就是有点难理解而已&#xff0c;它避免了普通队列的缺点&#xff0c;一样有队列头&#xff0c;队列尾&#xff0c;一样是先进先出的原则。我们采用顺时针的方式来对队列进行排序。 队列头(front) :允许进行删…

一道亚马逊算法面试题的情景分析

阅读博客的朋友可以观看视频&#xff1a; http://study.163.com/course/courseMain.htm?courseId1002942008 我们聚焦于一道亚马逊的算法面试题&#xff0c;通过分析该题&#xff0c;复盘它的解题情景&#xff0c;我们可以初步体会到算法面试的应对步骤&#xff0c;并从中窥…

LeetCode刷题笔记 标准模板库巧解算法题 优先队列

优先队列简介 ​ 优先队列&#xff08;priority queue&#xff09;可以在 O(1) 时间内获得最大值&#xff0c;并且可以在 O(log n) 时间内取出最大值或插入任意值。 ​ 优先队列常常用堆&#xff08;heap&#xff09;来实现。堆是一个完全二叉树&#xff0c;其每个节点的值总…

Python数据结构与算法(3.4)——队列相关应用与习题

Python数据结构与算法(3.4)——队列相关应用与习题 0. 学习目标1. 使用两个栈实现一个队列2. 使用两个队列实现一个栈3. 栈中元素连续性判断4. 重新排列队列中元素顺序5. 反转队列中前 m 个元素的顺序相关链接0. 学习目标 我们已经学习了队列的相关概念以及其实现,同时也了…

第十七章 优先队列优化Dijkstra算法

第十七章 优先队列优化Dijkstra算法 一、普通dijkstra算法的缺陷1、选出最小距离的过程&#xff1a;2、松弛所有点的过程&#xff1a; 二、如何优化1、代码模板&#xff08;1&#xff09;问题&#xff1a;&#xff08;2&#xff09;模板&#xff1a; 2、详细解读 三、优化分析1…

【自顶向下模块化编程】C语言实现多级反馈队列调度算法

自顶向下-多级反馈队列 多级反馈队列算法算法原理算法描述题目摘要 自顶向下模块化设计整体框架具体实现GeneratorSchedulerExecutor 整体代码实现 总结及心得总结心得 多级反馈队列算法 多级反馈队列调度算法是一种CPU处理机调度算法&#xff0c;UNIX操作系统采取的便是这种调…

[算法] 栈和队列

欢迎来到老胡的算法解题思路&#xff0c;本文章主要使用的语言为java&#xff0c;使用的题型为力扣算法题&#xff0c;基于这一篇文章&#xff0c;我将为你介绍栈和队列的基础知识和栈和队列的题型&#xff0c;喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&#xff01; 目…

十道经典面试算法真题详解

前言 分享一下 腾讯常考的十道算法题&#xff08;真题&#xff09;。在金三银四&#xff0c;希望对大家有帮助呀。 重排链表 最长递增子序列 环形链表 反转链表 最长回文子串 全排列 LRU 缓存 合并K个升序链表 无重复字符的最长子串 删除链表的倒数第 N 个结点 1. …

队列相关习题

1.已知循环队列存储在一维数组A0…n-1]中&#xff0c;且队列非空时front和rear分别指向队头元素和队尾元素。若初始时队列为空&#xff0c;且要求第一个进入队列的元素存储在A[0]处&#xff0c;则初始时front和rear的值分别是( )。 A.0&#xff0c;0 B. 0&#xff0c;n-1 C. n-…

java算法面试题_Java算法面试题汇总

原标题&#xff1a;Java算法面试题汇总 1. 字符串 如果IDE没有代码自动补全功能&#xff0c;所以你应该记住下面的这些方法。 toCharArray() // 获得字符串对应的char数组 Arrays.sort() // 数组排序 Arrays.toString(char[] a) // 数组转成字符串 charAt(int x) // 获得某个索…

详解单调队列算法

前言 嘿!彩蛋!感觉有帮助就三连呗! 如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。 在上一篇文章中,我们介绍了「单调栈」这一最常考察的线性数据结构。而今天我们将继续沿着这个思路,介绍另…

栈和队列相关经典算法题总结(数据结构+C语言)

我们这里针对栈和队列的一些经典算法题做详细讲解: 1.括号匹配问题. 2.用队列实现栈. 3.用栈实现队列. 4.设计循环队列. 一.详细讲解如下: 1.括号匹配问题.(如下图) 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &am…

qt使用消息队列服务器,qt代码实现消息队列通信

qt代码实现消息队列通信 内容精选 换一换 HBase 1.X版本在RPC流程中&#xff0c;多个数据通信线程会争抢同一个缓存Buffer队列&#xff0c;代码以lock重入锁实现线程安全&#xff0c;锁抢占严重&#xff0c;导致HBase不能充分发挥CPU多核的能力。HBase 1.X版本的RPC通信机制中B…

消息队列MQ常见面试题

面试官在面试候选人时&#xff0c;如果发现候选人的简历中写了在项目中使用了 MQ 技术&#xff08;如 Kafka、RabbitMQ、RocketMQ&#xff09;&#xff0c;基本都会抛出一个问题&#xff1a;在使用 MQ 的时候&#xff0c;怎么确保消息 100% 不丢失&#xff1f; 这个问题在实际…

RabbitMQ消息队列常见面试题总结

1、什么是消息队列&#xff1a; 1.1、消息队列的优点&#xff1a; &#xff08;1&#xff09;解耦&#xff1a;将系统按照不同的业务功能拆分出来&#xff0c;消息生产者只管把消息发布到 MQ 中而不用管谁来取&#xff0c;消息消费者只管从 MQ 中取消息而不管是谁发布的。消息…

【消息队列】面试题及答案整理

消息队列面试题 为什么要使用消息队列/消息队列的应用场景使用了消息队列会有什么缺点如何保证消息队列是高可用的RocketMQ是如何保证消息队列是高可用的 如何保证消息不被重复消费/如何保证消息消费的幂等性如何保证消费的可靠性传输RocketMQ如何保证消费的可靠性传输RabbitMQ…

JAVA——快速排序(详细)

JAVA快速排序的实现 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高&#xff0c;因此经常被采用&#xff0c;再加上快速排序思想----分治法也确实实用&#xff0c;因此很多软件公司的笔试面试&#xff0c;包括像腾讯&#xff0c;微软等知名IT公司都喜欢考这个&…

快速排序算法(java实现)

基本思想 快速排序是一种采用分治法解决问题的一个典型应用&#xff0c;也是冒泡排序的一种改进。它的基本思想是&#xff0c;通过一轮排序将待排记录分割成独立的两部分&#xff0c;其中一部分均比另一部分小&#xff0c;则可分别对这两部分继续进行排序&#xff0c;已达到整…

java快速排序(含快速排序代码)

目录 一&#xff1a;快速排序思想 二&#xff1a;快速排序代码&#xff08;pivot一定时先和arrays【r】先比较&#xff09; 三&#xff1a;结果 一&#xff1a;快速排序思想 假设我们现在对“6 1 2 7 9 3 4 5 10 8”这个10个数进行排序。首先在这个序列中随便找一个数作为基准…