基础算法--枚举

news2024/11/25 18:34:51

枚举算法是一种简单而有效的算法,它通过枚举所有可能的情况来解决问题。它通常用于解决问题规模比较小的问题,因为它的时间复杂度很高,随着问题的规模增加,算法的效率会急剧下降。

枚举算法的基本思路是通过循环遍历所有可能的情况,找到最优解或满足条件的解。它的步骤通常包括:

1.选择一个变量作为枚举变量,并确定它的取值范围。

2.在循环过程中遍历所有可能的取值,并执行某种操作。

3.检查每个可能的解是否符合要求,如果符合要求就记录下来。

4.在所有可能的解中,选择最优解或满足特定条件的解。

枚举作为一个基础的算法,除了与模拟算法有着密不可分的关系,还对解决一些线性表的问题有很大帮助。在解决线性表的问题中,枚举分为:线性枚举、二分枚举、三分枚举。在算法中,又可以分为暴力枚举(穷举法)、排列组合枚举、状压DP。这些算法都有其特定的适用场景和优缺点,需要根据具体的情况选择合适的算法。

叽里咕噜一大堆,今天带你认识一下各种词汇,别被它的名字给吓到,也许有些知识你学过但是你并不知道它的官方叫法而已。


一、线性枚举

简介:

线性枚举指的是遍历某一个一维数组(顺序表)的所有元素,找到满足条件的那个元素并且返回,返回的可以是下标,也可以是元素本身。由于是遍历的,穷举了所有情况,所以一定是可以找到解的,除非问题本身无解。一些资料上也称之为暴力算法(Brute Force)

练习:

给出一个数组:int* arr[10]={3,6,2,5,8,9,7,4,1,0};要求找到7所在位置的下标是多少。

int fuc(int* arr,int n,int targ){
    //arr={......};n=10;targ=7
    for(int i=0;i<n;i++){
        if(arr[i]==targ)return i;
    }
    return NULL;
}

总结: 

线性模拟就是循环遍历的一种叫法,时间复杂度O(n),认识即可。ok~技能树成功点亮了一叶。

二、二分枚举

简介:

如果在顺序表是有序的情况下,我们可以采取折半的方法去查找,这种方法称为二分枚举。

二分传送门:查找算法--二分查找-CSDN博客

练习:

洛谷2440-木材加工(这道题在上面传送的那个文章中讲过)

木材厂有 𝑛 根原木,现在想把这些木头切割成 𝑘k段长度为 𝑙的小段木头(木头有可能有剩余)。当然,我们希望得到的小段木头越长越好,请求出 𝑙的最大值。木头长度的单位是 cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

例如有两根原木长度分别为 11和 21,要求切割成等长的 6 段,很明显能切割出来的小段木头长度最长为 5。

#include<vector>
#include<algorithm>
#include<iostream>

using namespace std;
int maxLength(vector<int> v, int k)
{
    //二分的前提是顺序表有序
	sort(v.begin(), v.end());
	int m = v[v.size()-1];

	int left = 0;
	int right = m;
	int mid = (right - left) / 2 + left;

	while (left < right)
	{
		if (right-left == 1) {//如果木段差==1,就该考虑返回left还是返回right
			int s = 0; 
            for (auto e : v) {
				s += (e / right);
			}
			if (s >= k)return right;//如果总段数大于k说明至少能截成k个right.
			return left;//没能进入返回
		}

		int sum = 0;//段数和
		for (auto e : v) {
			//每根原木的长度÷估计的最大段长->可截段数
			//每根原木的可截段数 求总和
			sum += (e / mid);
		}

		//二分
		if (sum >= k) {
			//根据中值求总段数,可以获得比标准数量更多的小木段
			//那么可以试着大一点,更新左值
			left = mid;
		}
		else if (sum < k) {
			//根据中值不能获取足够的小木段
			//那么可以试着小一点,更新右值
			right = mid-1;
		}
		mid = (right - left) / 2 + left;//中值--更新mid
	}//时间复杂度O(nlogn),此时n为最短元素大小
	return mid;//结果理论为:left==mid==right
}
int main()
{
	int N, K; //N原木个数,K目标段数
	cin >> N >> K;
	vector<int> v(N);
	for (int i = 0; i < N; i++)
		cin >> v[i];//每根原木长度

	cout << maxLength(v, K) << endl;
	return 0;
}

总结:

这就是我们的二分法,时间复杂度为O(logn)。是不是又是一个熟悉的知识点。掌握了就在这个知识点的后面打上√吧。

三、三分枚举

简介:

三分枚举是一种用于求解单峰(单谷)函数极值的算法。它的基本原理是利用函数的单峰(单谷)性质,通过迭代的方式逐步缩小搜索范围,最终找到极值点。具体来说:对于形如y=ax²+bx+c的二次函数,其极值点位于x=-b/2a。如果给定一个包含极值点的区间,可以通过三分法逐步缩小区间范围,直到找到极值点。

练习:

牛客练习赛59-C.装备合成

牛牛有x件材料a和y件材料b,用2件材料a和3件材料b可以合成一件装备,用4件材料a和1件材料b也可以合成一件装备。牛牛想要最大化合成的装备的数量,于是牛牛找来了你帮忙。


输入包含t组数据
第一行一个整数t
接下来t行每行两个整数x,y

每组数据输出一行一个整数表示答案。

假设方案一做了m件装备,方案二做了n件装备,我们遍历m来求n,n=min((x-2m)/4, y-3m),三分m,求n+m的最大值

由于三分时返回的m+n是整数,注意下面的情况时check(mid1)==check(mid2)&&check(mid1)<check(R) ,L=mid1+1,而不是R=mid2-1

#include <bits/stdc++.h>
using namespace std;

int x, y;
int check(int m){
    return m+min((x-2*m)/4, y-3*m);
}
int main(){   
    int T;
    cin>>T;
    while(T--){
       cin>>x>>y;
       int L=0, R = min(x/2, y/3);
       int ans = 0;
       while(L<=R)
       {
           int mid1 = L+(R-L)/3, mid2 = R-(R-L)/3;
           int res1 = check(mid1), res2 = check(mid2);
           ans = max(res1, res2);
           if(res1<res2||(res1==res2&&res1<check(R))) L = mid1+1;
           else R = mid2-1;
       }
       cout<<ans;
    }
    return 0;
}

 总结:

三分枚举算法常用于求解优化问题,特别是在没有明显规律可循的环境中。例如,在处理山峰高度调整问题时,可以通过三分枚举算法来最小化山峰之间的最大高度差。具体应用场景包括但不限于调整山峰高度、优化资源配置等。

三分枚举算法的优点在于其简单易懂,适用于求解单峰(或单谷)函数的极值问题。然而,它的缺点也很明显,即效率较低,特别是在处理大规模数据时,可能会消耗较多的计算资源。此外,三分枚举算法依赖于函数的单峰(或单谷)性质,如果函数不满足这一性质,算法将无法正确工作。


四、暴力枚举

简介:

暴力枚举,顾名思义,就是将问题的所有可能解逐一列举出来,然后一一验证,直到找到正确解。这种方法虽然看似粗暴,但对于规模较小的问题或者没有更优解法的情况下,往往是最直接有效的方法。数组的线性枚举就是暴力枚举的一种。

练习:

X星系的机器人可以自动复制自己。它们用1年的时间可以复制出2个自己,然后就失去复制能力。
每年X星系都会选出1个新出生的机器人发往太空。也就是说,如果X星系原有机器人5个,
1年后总数是:5 + 9 = 14
2年后总数是:5 + 9 + 17 = 31
如果已经探测经过n年后的机器人总数s,你能算出最初有多少机器人吗?


输入:输入一行两个数字n和s,用空格分开,含义如上。n不大于100,s位数不超过50位。
输出:要求输出一行,一个整数,表示最初有机器人多少个。

从有一个开始试,试到n年,看此时的结果是不是输入的总人数。是就输出并退出,不是的话就继续。今年能产生的机器人数量=去年的*2-1。然后把今年产生的加在总count里。判断count和输入的一不一样。

#include <iostream>
using namespace std;

#define Long long long
int main() {
    int n;
    Long total,count = 0;
    Long thisYear=0,lastYear=0 ;
    cin >> n >>total;
    for (int i = 1; i < total; ++i) {
        count = thisYear = i;
        for (int j = 0; j < n; ++j) {
            lastYear = thisYear;
            thisYear = lastYear*2-1;
            count += thisYear;
        }
        if (count == total) {
            cout << i;
            return 0;
        } 
        //else continue;
    }
}

 五、排列组合枚举

简介:

1. 排列枚举:给定 n 个元素,枚举其所有的 r 元素排列可以使用递归或回溯的方法。

2. 组合枚举:同样地,组合的枚举也可以使用递归的方式来实现。

递归传送门:基础算法--递归算法【难点、重点】-CSDN博客

练习:

生成给定数组的所有排列组合:

#include <iostream>  
#include <vector>  
#include <algorithm>  
using namespace std;

void permute(vector<int>& nums, int start) {  
    if (start == nums.size() - 1) {  
        // 输出当前排列  
        for (int num : nums) {  
            cout << num << " ";  
        }  
        cout << endl;  
    } 
    else {  
        for (int i = start; i < nums.size(); ++i) {  
            swap(nums[start], nums[i]); // 交换  
            permute(nums, start + 1);        // 递归  
            swap(nums[start], nums[i]); // 撤销交换  
        }  
    }  
}  

void combine(const vector<int>& nums, int r, int start, vector<int>& path) {  
    if (path.size() == r) {  
        // 输出当前组合  
        for (int num : path) {  
            cout << num << " ";  
        }  
        cout << endl;  
        return;  
    }  
    for (int i = start; i < nums.size(); ++i) {  
        path.push_back(nums[i]); // 添加当前元素  
        combine(nums, r, i + 1, path); // 递归  
        path.pop_back(); // 撤销添加  
    }  
}  

int main() {  
    vector<int> vec = {1, 2, 3};  
    permute(vec, 0);  

    vector<int> nums = {1, 2, 3};  
    int r = 2; // 组合的大小  
    vector<int> path;  
    combine(nums, r, 0, path);  
    return 0;  
}
  • 排列枚举: 这个程序通过交换当前元素和其他元素的位置,然后递归处理下一个位置,最终列出所有可能的排列。
  • 组合枚举: 这个程序通过递归构建组合,每次选择当前元素并继续下一次迭代。通过 path 存储当前组合,达到组合大小后输出结果。

六、状压DP

em,我还没学,不太会,就不讲了。谅解谅解,嘻嘻。


感谢观看!

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

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

相关文章

(C语言贪吃蛇)13.实现贪吃蛇四方向的移动

目录 前言 原代码预览 解决方法⚠️ 运行效果 总结 前言 我们上节通过Linux线程实现了两个while(1)同时运行&#xff0c;这样就可以一边控制方向一遍刷新出贪吃蛇的身体节点了。本节我们就来实现贪吃蛇四方向的移动。 (此图片为最终效果) 原代码预览 我们之前的代码是通过…

6.模拟电子技术——共集电极,共基极,多极放大电路

写在前面 这个是第六次的笔记&#xff0c;祝大家学习愉快 笔记部分 1.共集电极放大电路 首先&#xff0c;我们再复习一遍组态判断&#xff1a;基极进&#xff0c;发射极出&#xff0c;说明是共集电极放大电路。可能读者已经知道一些结论&#xff0c;先抛开这些&#xff0c;我…

Kubernetes-环境篇-02-ubuntu开发环境搭建

1、ubuntu基础环境 # 更新apt软件源 sudo apt update# 安装git sudo apt install git# 安装python3 sudo apt install -y python3 python3-pip# 安装vim sudo apt install vim2、安装go 2.1 下载go安装包 wget https://golang.google.cn/dl/go1.23.2.linux-amd64.tar.gz2.2 …

第十二届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)(第一套)

一.题目分析 &#xff08;1&#xff09;.题目 &#xff08;2&#xff09;.题目分析 1.串口功能分析 a.串口接收车辆出入信息&#xff1a;通过查询车库的车判断车辆是进入/出去 b.串口输出计费信息&#xff1a;输出编号&#xff0c;时长和费用 c.计算停车时长是难点&#x…

深度学习-----------------机器翻译与数据集

目录 机器翻译与数据集下载和预处理数据集预处理步骤词元化词汇表该部分总代码 固定长度阶段或填充该部分总代码 转换成小批量数据集用于训练训练模型总代码 机器翻译与数据集 import os import torch from d2l import torch as d2l下载和预处理数据集 #save d2l.DATA_HUB[fr…

被字节恶心到了

字节 日常逛 xhs 看到一篇吐槽贴&#xff0c;表示被公司恶心到了&#xff1a; 这位网友表示&#xff0c;最近是公司举办了 Q2 和 H1 的优秀员工表彰&#xff0c;自己的 1&#xff08;直属领导&#xff09;评上了&#xff0c;但仔细一看&#xff0c;1 获奖的所有产出都是自己的&…

sql注入第7关(学习记录)

看到这里好像和前面的不一样了&#xff0c;多了个use outfile 先输入个符号&#xff0c;看报错&#xff0c;还是得看别人的教程&#xff0c;通过查找&#xff0c;好像要通过图片来进行注入&#xff0c;ok呀&#xff0c;又是新的方式&#xff0c; 首先我们需要知道他的闭合方式…

uniapp+Android智慧居家养老服务平台 0fjae微信小程序

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 老年人 登…

算法 | 鹈鹕算法POA-Transformer-LSTM多变量回归预测

&#x1f525; 内容介绍 近年来&#xff0c;随着大数据时代的到来和计算能力的飞速提升&#xff0c;对复杂系统进行精确预测的需求日益增长。多变量时间序列预测作为一项关键技术&#xff0c;广泛应用于金融、能源、交通等诸多领域。传统的预测方法&#xff0c;例如ARIMA和多元…

Prometheus Metrics和PromQL的使用

Metrics 官方解释是 Metrics are numerical measurements in layperson terms. (通俗地讲&#xff0c;Metrics就是数字测量) Prometheus fundamentally stores all data as time series &#xff08;Prometheus把所有数据都存储为时间序列&#xff09; Every time series is u…

《PMI-PBA认证与商业分析实战精析》第6章 跟踪与监督

第6章 跟踪与监督 本章主要内容包括&#xff1a; 跟踪 关系与依赖性 批准需求 基线化已批准需求 使用跟踪矩阵来监督需求 需求生命周期 管理需求变更 本章涵盖的考试重点&#xff1a; 跟踪与监督的六项活动 跟踪与监督六项活动的可交付成果及活动间的关系 跟踪的定义…

指南:Linux常用的操作命令!!!

引言: 操作系统是软件的一类。 主要作用是协助用户调度硬件工作&#xff0c;充当用户和计算机硬件之间的桥梁。 尽管图形化是大多数人使用计算机的第一选择&#xff0c;但是在Linux操作系统上多数都是使用的&#xff1a;命令行在开发中&#xff0c;使用命令行形式&#xff0c…

【有啥问啥】联邦学习(Federated Learning, FL):保护隐私的分布式机器学习

联邦学习&#xff08;Federated Learning, FL&#xff09;&#xff1a;保护隐私的分布式机器学习 联邦学习&#xff08;Federated Learning, FL&#xff09;作为一种前沿的分布式机器学习技术&#xff0c;正逐步成为解决数据隐私保护与模型性能提升之间矛盾的关键方案。以下是…

HTTP Cookie与Session

目录 一. 引入Cookie 1.1 定义 1.2 工作原理 1.3 分类 二. 认识Cookie 三. 测试Cookie 五. 引入Session 六. 测试Session 这篇博客&#xff0c;我们来看看Cookie与Session&#xff0c;内容干货满满。 一. 引入Cookie 1.1 定义 HTTP Cookie&…

幂等性及技术解决方案

目录 定义幂等性 为什么需要幂等性幂等性设计注意事项幂等性的范围分布式锁解决幂等性 设计 延伸阅读 定义幂等性 简单地说&#xff0c;我们可以多次执行幂等运算而不改变结果或者使用相同的输入参数中被调用多次&#xff0c;则不具有额外效果的操作&#xff0c;也就是多次执…

使用pytdx获取历史股票行情

使用pytdx获取历史股票行情 先看效果pytdx基础获取历史股票行情将历史数据存入数据库 先看效果 获取从2010年01月01日-2024年09月30日的股票数据 pytdx基础 https://blog.csdn.net/firexiaHouse/article/details/142687052?spm1001.2014.3001.5501 获取历史股票行情 def …

C++11--智能指针

引入 为什么需要智能指针&#xff1f; 在介绍异常时&#xff0c;遇到以下场景&#xff0c;处理异常就会比较棘手&#xff1a; void Func() {int* arr1 new int[10];int* arr2 new int[20];int* arr3 new int[30];// ...delete[] arr1;delete[] arr2;delete[] arr3; }这里…

一文吃透 SpringBoot (从入门到精通)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

15分钟学 Python 第35天 :Python 爬虫入门(一)

Day 35 : Python 爬虫简介 1.1 什么是爬虫&#xff1f; 网页爬虫&#xff08;Web Crawler&#xff09;是自动访问互联网并提取所需信息的程序。爬虫的主要功能是模拟用户通过浏览器访问网页的操作&#xff0c;从而实现对网页内容的批量访问与信息提取。它们广泛应用于数据收集…

【IPv6】IPv6地址格式及地址分类(组播、单播、任播)整理

IPv6地址格式 IPv6 地址从 IPv4 地址的 32 bits 扩展到 128 bits&#xff0c;IPv6 地址的表示、书写方式也从 IPv4 的点分十进制&#xff0c;修改16进制的冒号分割 IPv4 点分格式(.) 192.168.11.11 IPv6 冒号分割(:) 2408:8459:3032:0000:0000:0000:0001:a9fd IPv6 的规范…