暑期集训(6) 栈与DF

14 篇文章 0 订阅
12 篇文章 0 订阅
本文探讨了栈的基本概念、手写和STL栈的实现,以及如何利用栈模拟栈操作和解决括号匹配问题。同时,深入解析了DFS的定义、递归与栈实现,介绍了剪枝策略,包括最优性、重复性、奇偶性和可行性剪枝,并通过实例展示了它们在实际问题中的应用。
摘要由CSDN通过智能技术生成

一.栈

1.定义

一种受限制的线性表,我们可以操作的……只有最后一个元素
我们可以从栈的最后插入一个元素,知道最后面的元素是什么,可以把最
后面的元素删了,其它的都做不了

元素先进后出,像极了第一个进入了电梯被挤得下不去的你
我们可以操作的这一头,被称为栈顶

2.两种写法

栈可以分为手写栈和STL栈

手写

const int maxn=100010;
int/char sta[maxn]; //stack是特殊定义,不能做数组名,其实就是STL的栈
int top=0;
..............
stack[++top]=s[i];

手写栈要注意栈顶的数值

STL

stack <int/char> sta;//这里不用开大小

个人理解STL栈是更为方便的,较多的函数简洁明了,就是检查打表时有些麻烦

3.STL特殊函数

在这里插入图片描述

4.例题

<1>模拟栈

实现一个栈,栈初始为空,支持四种操作:

(1) “push x” – 向栈顶插入一个数x;

(2) “pop” – 从栈顶弹出一个数;

(3) “empty” – 判断栈是否为空;

(4) “query” – 查询栈顶元素。

现在要对栈进行M个操作,其中的每个操作3和操作4都要输出相应的结果。

输入格式 第一行包含整数M,表示操作次数。

接下来M行,每行包含一个操作命令,操作命令为”push x”,”pop”,”empty”,”query”中的一种。

输出格式 对于每个”empty”和”query”操作都要输出一个查询结果,每个结果占一行。

其中,”empty”操作的查询结果为“YES”或“NO”,”query”操作的查询结果为一个整数,表示栈顶元素的值。

数据范围 1≤M≤100000, 1≤x≤109 所有操作保证合法。

1)思路

比较简单,使用STL栈的内置函数即可

2)代码实现
电脑重启保护,文件没了....

<2>括号匹配加强版

在这里插入图片描述

思路

比较繁琐,先是简易思路,就像括号匹配一样,是左括号就入栈
右括号检测top的右括号是否配对,配对栈顶就减一,出栈
但是注意输出的内容,分析一下是最长的配对括号
这时候我们就开一个标记数组,值全部定为false
当出栈时,将两个括号在标记数组中的值改为true
最后遍历标记数组,寻找最长的true值序列即可
有一些细节
在记录标记数组时,显然是左右括号的位置
右括号下标好求
但左括号却没有那么简单
因为栈顶的下标一直是在变化的
可能不是最开始输入的下标
所以我们开一个结构体
分别记录括号的值与输入时的下标
最后即可标记
判断时开一个maxx
每次比较maxx与标记数组连续子序列为true的长度
输出maxx即可

代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
struct QA
{
	int id;
	char kh;
//	bool flag=false;
}sta[maxn];
int maxx=-maxn;
int t;
int sum=0;
bool f[maxn];
string s;
int top=0;

int main()
{
	
//	freopen("LongestRegularBracketsSequence.in","r",stdin);
//	freopen("LongestRegularBracketsSequence.out","w",stdout);
	
	cin>>s;
	for(int i=0;i<s.size();i++)
	{
		if( s[i]=='(' || s[i]=='[' )
		{
			top++;
			sta[top].kh=s[i];
			sta[top].id=i;
		}
		
		else if((s[i]==')' && sta[top].kh=='(') || (s[i]==']' && sta[top].kh=='['))
		{
//			sta[s[i]].flag=true;
			f[i]=true;
//			sta[sta[top].id].flag=true;
			f[sta[top].id]=true;
			top--;
		}
		
		else top=0;
	}
	

	
	for(int i=0;i<s.size();i++)
	{
		
		
		if(/*sta[i].flag*/ f[i] /*&& sta[i+1].flag*/)
		{
			sum++;
		}
		
		
		
		if(!f[i] /*&& (!sta[i+1].flag)*/)
		{
			if(maxx<sum)
			{
				maxx=sum;
				t=i;			
			}
			sum=0;
		}
		
	}
	
/*	for(int i=t-maxx;i<=t-1;i++)
	{
		cout<<s[i];
	}
*/
	cout<<t;
		
	return 0;
}

二.搜索之DFS

1.定义

搜索是已知初始状态和目标状态,对问题的中间状态进行枚举和遍历的一种解题算法,所以说搜索是一种变化的和复杂的枚举。

搜索从本质上来说是枚举,但搜索更灵活,更加能够体现智能逻辑的魅力。基于枚举思想的搜索相对单纯的枚举有许多不可替代的优势。

2.如图

在这里插入图片描述
在这里插入图片描述

3.两种写法

DFS可以用递归实现,也可以用栈实现
DFS不一定在图中,有很多DFS暴力递归搜索解决问题
经常用来解决无法确定该写几层循环的题

递归

在这里插入图片描述

利用栈的先进后出的特点实现的,可以采用
递归的方法来完成。

4.剪枝

深度优先搜索,是从初始状态起,利用一定的规则生成搜索树,寻找下一层任一个结点,检查是否出现目标状态,若未出现,以此状态利用规则生成再下一层任一个结点,再检查,重复过程一直到叶节点(即不能再生成新状态节点),当它仍不是目标状态时,回溯到上一层结果,取另一可能扩展搜索的分支。采用相同办法一直进行下去,直到找到目标状态为止。

剪枝,就是减小搜索树规模、尽早排除搜索树中不必要的分支的一种手段。形象地看,就好像剪掉了搜索树的枝条,故称之为“剪枝”。在深度优先搜索中,有以下几类常见的

最优性剪枝

1)定义

对于求最优解的一类问题,通常可以用最优性剪枝,比如在求迷宫最短路的时候,如果发现当前的步数已经超过了当前最优解,那从当前状态开始的搜索都是多余的,因为这样搜索下去永远都搜不到更优的解。通过这样的剪枝,可以省去大量冗余的计算。此外,在搜索可行解的过程中,一旦找到一组可行解,后面所有的搜索都不必再进行了,这算是最优性剪枝的一个特例。

2)方式&例题

在这里插入图片描述

重复性剪枝

1)定义

对于某一些特定的搜索方式,一个方案可能会被搜索很多次,这样是没必要的
减去重复的情况

2)方式&例题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

奇偶性剪枝

1)定义

当有规律可寻的dfs时,减去重复的一部分

2)方式&例题

在这里插入图片描述
在这里插入图片描述

可行性剪枝

1)定义

所谓可行性剪枝,就是把能够想到的它不可能出现的情况给它剪掉,对于每一个数,我们有两种选择:选或不选;在这其中,我们用cnt记录了选择数的个数,如果当选择个数cnt==k时,这时再往后选更多的数是没有意义的。所有我们可以直接减去这个搜索分支:

2)方式&例题

在这里插入图片描述
在这里插入图片描述

5.例题

见上即可

总结

1.栈的使用适合于一些特殊的题目,在先进后出的线性表结构下,不存在栈的下标,但节省了内存,并且一般不会超时
2.暴力搜索可以使我们尽量减少代码运行时间,拿到更多的 分数,但有时候不无脑,考虑剪枝,或者与贪心结合,能让题目A的可能性更大

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值