第八周ACM总结

本周深入学习了并查集的查找、合并、路径压缩及其在连通性、最小生成树等问题中的应用,拓扑排序则用于有向无环图的排序和验证。分享了'畅通工程'和'感染病毒'实例,以及DFS和BFS在搜索题中的心得。策略技巧包括并查集的多种结合方式和拓扑排序的应用场景。
摘要由CSDN通过智能技术生成

这一周呢,自己主要学习的是并查集和拓扑排序的资料,也稍微看了一部分相关的题型。除此之外,这一周也在继续看老师发的95道左右的搜索题目,并有了自己的一些心得。下面是这一周的具体总结。

对并查集、拓扑排序的理解

一、并查集

就是一种维护集合的数据结构,一个是查找,一个是合并。基本的定义就是用数组实现,比如father[1]=2,代表元素1的父亲节点是元素2。

1、查找

基本原理,就是一个集合只存在一个根节点,寻找根节点的标志就是father[i]==i,满足这个条件就是根节点了。基本思路,可以用递推或者是递归来实现,用一个while循环,反复寻找根节点。

2、合并

基本原理,就是把其中一个集合的根节点的父亲指向另一个集合的根节点。基本思路,就是先判断是否属于同一集合,然后再开始进行合并,把其中一个集合的父亲结点指向另一个结点就能实现了。并查集产生的每一个集合都是一棵树,不会有环出现。注意事项,一定要先寻找根节点,不能直接将其中一个元素的父亲设为另一个元素,否则达不到合并效果。

3、路径压缩

1、路径压缩主要是针对优化查找操作的,因为如果元素数量多,而且在最后边,效率很低。基本原理,就是把当前查询结点的路径上的所有结点的父亲都指向根节点。基本思路,先按原来写法获得一个元素的根节点,重新从这个元素走一遍寻找根节点的过程,把经过的所有结点的父亲全部改成根节点,也可以用递归来实现。
2、优化的方法还有一个是按秩合并,合并的时候将元素少的集合合并到元素多的集合中,合并之后树的高度会相对较小。

4、并查集应用

应用,求无向图的连通分量个数,最近公共祖先,求最小生成树等等。

5、并查集例题

例题:畅通工程
题意呢,就是问还需要修建多少条路,使得各个城镇之间实现联通。

基本思路,就是先将所有的元素初始化,然后再将各个元素根据题目要求建立集合关系,最后查询有几个根节点,就说明有几个独立的集合,然后把他们的根节点连起来就可以实现联通,连接了多少次就需要修建多少条道路。
下面给出大佬代码,很好理解。

#include<stdio.h>
int father[1005];
int Find(int x)
{

    while(x!=father[x])
        x=father[x];
    return x;    
}
void Combine(int a,int b)
{
    int fa=Find(a);
    int fb=Find(b);
    if(fa!=fb)
    {
        father[fa]=fb;
    }
}
int main()
{
    int n,m;
    int i;
    int a,b;
    while(~scanf("%d",&n))
    {
        if(n==0)
        break;
        scanf("%d",&m);
        int sum=0;
        for(i=1;i<=n;i++)
            father[i]=i;
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            Combine(a,b);
        }
        for(i=1;i<=n;i++)
        {
            if(father[i]==i)
                sum++;    
        }    
        printf("%d\n",sum-1);
    }
    return 0;
}

例题:感染病毒

这个比上边那个稍微复杂了些,但是基本思路还是一致的。题意呢,就是说一个集合中的某个元素可能感染病毒,同集合中也可能被感染,给出分组,问感染人数。

基本思路,查询祖先结点,祖先节点不一致,让二者中某一个认另一个为祖先,这样就在同一个集合中了,最后查询人数即可,也可以用状态压缩,让他们都指向同一个祖先结点,可以加快速度。如下代码所示。

int find(int x)
{
    if(x!=pre[x])

        //找到其祖先节点,并将其父节点变成找到的祖先节点
        pre[x] = find(pre[x]);  

    //由父节点继续向上递归查询
    return pre[x]; 
}

二、拓扑排序

1、基本思路和应用

拓扑排序感觉稍微复杂了些,有一部分些内容还没有看懂。先说拓扑序列吧,就是将有向无环图的所有顶点排成线性序列,在这个图中的任意两个顶点,存在一定的指向方向关系,例如a->b,a一定在b的前面,这个序列成为拓扑序列,通俗的理解就是类似于学习某一门课,学完特定的课程之后才能学习下一门,顺序唯一,而有些科目没有一个先后的学习顺序,顺序不唯一。拓扑排序呢,意思是说,将有向图中的顶点以线性方式进行排序,就是拓扑排序。

基本思路,可以用邻接表实现拓扑排序,也要定义数组记录结点的入度。具体操作就是定义一个队列,把所有入度为零的结点接入队列,取出队首结点并输出,删去从它出发的所有边,并且让这些边到达顶点的入度减一,某个顶点入度为零时,加入队列。重复以上操作即可,直到队列为空,如果入过队的结点数目恰好为n,拓扑排序就完成了。

应用,很重要的一个应用就是判断一个给定的图是否是有向无环图。如果拓扑排序成功,说明给定的图是有向无环图,否则,拓扑排序失败,不是有向无环图。
部分实现代码如下:

vector<int>G[MAXV];
int n, m, inDegree[MAXN];
bool topologicalSort() {
	int num = 0;
	queue<int>q;
	for (int i = 0; i < n; i++) {
		if (inDegree[i] == 0) {
			q.push(i);
		}
	}
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = 0; i < G[u].size(); i++) {
			int v = G[u][i];
			inDegree[v]--;
			if (inDegree[v] == 0) {
				q.push(v);
			}
		}
		G[u].clear();
		num++;
	}
	if (num == n) {
		return true;
	}
	else {
		return false;
	}


2、拓扑排序例题

例题:确定比赛名次
题意呢,就是说给定几支队伍,和几只队伍的输赢关系,求最终的排名顺序(按照编号顺序)。
一开始,自己对前面拓扑排序的实现思路还不大理解,但是看了这个题(有图形的描述),自己基本就明白了。

基本思路,就是要先根据题目描述的各个队伍之间的输赢关系,建立下面这样一张有向无环图,对顶点进行拓扑排序。先找到入度为零的点1和4,删去点1和与1相关的边,接着寻找入度为0的点,继续输出就可以了。
在这里插入图片描述
在这里插入图片描述

题型思路技巧概括

1、并查集题型,合纵连横并查集和最小生成树结合并查集和离散化结合并查集路径压缩和按秩合并并查集求连通块个数并查集和欧拉路、Trie树结合等等。
2、拓扑排序题型,确定比赛名次产生冠军拓扑和并查集结合拓扑排序和队列等等。
3、并查集的本质是维护传递性,也可以用来判环路,比DFS和BFS高效一些,可以找到所有环路。
4、拓扑排序的三种方法,无前趋的的顶点优先拓扑排序,无后继的的顶点优先拓扑排序,基于DFS递归的拓扑排序(逆序)。
5、一般无论是并查集还是拓扑排序,最好都要建立一个图,因为有些文字描述很抽象,这个时候如果能建立一张图,就很好理解了。
6、拓扑排序要保证没有环出现,而且拓扑排序的结果不一定唯一。

DFS和BFS题目AC心得

这周已经是第九周了,搜索专题也算是结束了,已经准备开始下一个专题了。90多道题目,基本看了一遍了,AC的题目数量不是很多,AC一道题基本就已经过去好长时间了。但是也是最终完成了看这90多道题的任务。

遇到的困难
1、首先一点吧,有的题目描述的很抽象,特别是中间靠后的一部分题目,有的还是英文,就有的时候很难读懂。
2、其次就是把思路转化成代码,自己AC的题目,基本都是思路比较清晰的,像是迷宫的,连通块的这一类,自己相对熟悉一些。其余的题目,可能有了思路,但是很难写出来,一般看了博客自己才能写出来。
3、还有就是看一道题目,有的比较长,自己就有的时候沉不下心来了,以后要改正。

一些小小收获
1、虽然遇到了不少困难,但是也有很多收获,即使没有做对题目,但是也有了对这些题目的认识,有自己的思考在里边,无论如何,都是有很大帮助的。同时也见识了更多的题目类型,搜索和其它知识结合的内容。
2、这些题目当中,遇见的比较多的是完全用DFS和BFS来做的题目,其次呢,是搜索和染色,搜索和联通块,搜索和图结合的题目,也有少数题目,用到了并查集,二分,环套树的一些知识。
3、自己做出来的题目,也并不是一帆风顺,得修改好几次,可能哪个边界没考虑,输出格式又出现了问题,还有各种的一些细节的地方自己没有考虑到,一般就是框架有了,但是让内容完善起来还有点难度。但是,反复调试并且AC的那一刻也是很让人高兴的。
4、总之吧,只要沉下心来,积极的去思考,总会有收获的,一些题型也是通过这样的反复练习,变得更加熟悉了,同时也见识了很多新颖的题目,像是我们的东方梦,机器人搬重物等题目。

反思规划
虽然搜索专题结束了,但是并查集和拓扑排序等知识也会不断到来。不能仅仅学完一个专题就想着放松了。还是自己之前下定的决心,既然做出了选择就一定会坚持下去,不会回头。以后会继续按照老师的思路,在学习的道路上继续坚持下去!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗紫色的乔松(-_^)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值