第八周周总结

前言:本周以及上周主要对搜索专题进行了代码练习,不止步于看题解,而是主动尝试解题。同时对图论中并查集进行了一定了解。

 

目录

ACM专题练习心得

并查集

P3367 【模板】并查集


ACM专题练习心得

其实说是a题,其实也a了一些普及/提高 级别的题目,此路仍然道远。在接下来完成专题练习的过程仍需要对这场专题练习中的部分题目重温。搜索专题练习中a的第一道题是一道有关连通块的DFS题目,也以此为模版,逐渐摸索对于一系列基础连通块问题的解题模版与思路。

接下来是数字排列类问题,如何在单纯穷举遍历的过程中制定规则进行剪枝来优化代码,很多时候我并不能很快想到一种巧妙的方法,也是在a这类题的时候,在很久没有思路无法ac的时候我开始尝试着暴力模拟,暴力枚举等方法将题目模拟来试图AC,虽然总是超时或者在某个通过点wrong导致无法完全AC但也能得到一部分分数。

当然在a题的过程中我也发现由于一些题目具有特殊的输入输出格式或者特殊的数据范围,往往需要灵活使用诸如:进制转换、模拟高精度、字符转换,等基础的技巧处理数据。

在接下来的几天里,我尝试尽量通过正解正解写出题目,再接下来就遇到了最简单的迷宫问题,矩阵中只含有路障,对于这种题在做题过程中也摸索出了一套模版,运用BFS可求出最短的路径。

接下来是大量的提高+的问题,诸如

P2867 Big Square S
P2919 Guarding the Farm S
P2937 Laserphones S
P1751 贪吃虫

这些问题大部分都涉及到了树并且由二叉树引申出了并查集、图论的知识,在看题解的过程中发现它们题解似乎不只是唯一,在洛谷的题解中有一些思路新颖,用不同的方式AC的题解,但是这些底层的逻辑都是要明白题名是在讲什么,将图模拟出来,当然在最开始的时候我只是去看大佬的题解都有一点点的吃力,于是我暂时跳过这段练习,在看后续问题的过程中对图论的基本概念进行了解,在最后又对这种题进行复读。

在复读的过程中,我明白这种题最基本的是要读懂题意,通过题意来将图模拟出来,无论是有向图还是无向图,总之要模拟出图,然后才能有下一步的思路,如何将图保存下来,然后基于所画的图进行搜索。对于其中延伸出来的知识,仍然需要在以后熟悉之后重新做一遍。

再次接触到的题由回到了迷宫问题,但不同的是有更多的约束条件,如何成功模拟这些问题并且在搜索过程中满足这些条件是我遇到的难点,对于这类问题我总是连看一个小时左右都不一定能够AC。

总的来说搜索题当然以BFS、DFS为最最核心的算法,但是不同的题目以深搜广搜为基础向外延伸拓展,从目前来看我仅仅掌握了最基本的代码思路,做题盲目性大,往往只能知道大致方向但是细枝末节无法准确完成(经常暴力枚举。。),距离快速准确的解决问题还有很长一段路。。


并查集

在学习过程中,并查集就相当于一种将元素分组,然后更高效的搜索元素的算法,将同属一组的元素都指向一个共同的根,比如元素1和2属于同一组、元素1和3也属于同一组,那么元素2和3能通过元素1合并为同一组,那么元素1就是元素2和元素3在并查集中的根。

在并查集的合并中,为避免出现退化要通过判断树的深度让小树的根指向大树的根。

P3367 【模板】并查集

一道经典的并查集模版题,思路首先是要找到根结点,然后写出合并的函数与查询的函数,提供了两个正整数n,m,表示有n个元素,m次询问。接着他给了你m行询问,一行询问有z,x,y三个数。当z=1时,将x与y所在的集合合并;当z=2时,输出x与y是否在同一集合内,是的话输出Y;否则话输出N。

int find(int x)
    {
    	if(f[x]==x)//如果一个元素的根结点就是它自己
    	{
    		return x;//就直接返回它自身
    	}
    	else
    	{
    		f[x]=find(f[x]);//否则就接下去寻找,直到找到他的根结点为止
    	}
    	return f[x];//返回它的根结点的值
    }

 AC代码

#include<bits/stdc++.h>
using namespace std;
int n,m,z[100023],x[100023],y[100023];
int s[100023];
int find(int x)
{
	if(s[x]==x)
	{
		return x;
	}
	else
	{
		s[x]=find(s[x]);
	}
	return s[x];
}
void work1(int x,int y)//合并
{
	s[find(y)]=find(x);
}
void work2(int x,int y)//查询
{
	if(find(x)==find(y))
	{
		cout<<"Y"<<endl;
	}
	else
	{
		cout<<"N"<<endl;
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>z[i]>>x[i]>>y[i];
		s[i]=i;
	}
	for(int i=1;i<=m;i++)
	{
		if(z[i]==1)
		{
			work1(x[i],y[i]);
		}
		else
		{
			work2(x[i],y[i]);
		}
	}
	return 0;
}


总结:对于并查集仍然理解的不够深刻,希望在下一个并查集专题期能够灵活使用这种算法吧,对于之前的搜索专题,温故知新,在学习之余对好题温习,毕竟搜索专题里大量有关图论、并查集、二叉树类问题并没有得到解决。任重道远吧。 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值