并查集总结:
#define N
int f[N];
void init(int k){
for(int i=1;i<=k;i++)
f[i]=i;
}
int find(int k){
if(k==f[k])
return k;
return f[k]=find(f[k]);
}
void Union(int a,int b){
int fa=find(a);
int fb=find(b);
if(fa!=fb)
f[fa]=fb;
}
1. 判断元素个数,集合个数之类
有几个这个就有几个集合
if(find(i)==f[i])
sum++;
元素的个数==同个根节点下有几个孩子
isRoot[find(i)]++;
2. 判断环
3. 需要加几条边能构成一个连通块
这两类问题主要是在 Union 函数中添加操作来实现。
判断环:
a,b之间的根节点如果相同=》a,b是联通的=》a,b之间已经存在了一条路了
当我们又添加了一条路的时候,就说明图中出现了环。
if(fa!=fb)
f[fa]=fb;
else
出现了环
2492 -- A Bug's Life (poj.org)
需要加几条边能构成一个连通块:
当sum=n-1时就成连通块了,
if(fa!=fb){
f[fa]=fb;
sum++;
}
前三类问题只要出现 集合,连接,集合中元素的个数 就往并查集想。
一般都会加一些限制:
合并时需要代价:
1. 要求达到效果(连通)时,所有消耗的代价的最大值最小。
实现:排序后,从小到大,在到达效果前无限加(都加进去)。
P1111 修复公路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
2. 要求达到效果(连通)时,所有消耗的代价的和的最小值。
实现:排序后,从小到大,只合并需要合并的(不能出现环)。
void Union(int a,int b,int c){
int fa=find(a);
int fb=find(b);
if(fa!=fb){
sum1++;//记录合并的次数
sum2+=c;// 能合并,才加上代价
f[fa]=fb;
}
}
P1195 口袋的天空 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
代价问题的核心都是按代价排序
一般用结构体存两点和代价
struct Node{
int x;
int y;
int t;
}ans[N];
bool cmp(const Node &a,const Node &b){
return a.t<b.t;
}
将数字换成字符串:
因为 f[i] 数组的值等于 i 数值时才判断是根节点,所以出现字符串的时候,我们就无法用数组来实现并查集。
map <string,string> f;
需要注意的是:如何初始化。当一个字符串是第一次出现的判断条件(当我们没有给字符串s 找“爹”时,它的“爹”是 "")是
f[s]==""
P2814 家谱 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
4. 带值并查集
1.需要树的高度。
用 rank[] 存高度,高的在低的上面(高的树是低的树的根节点);
void union(int x,int y)
{
x=find(x); //寻找 x的代表元
y=find(y); //寻找 y的代表元
if(x==y) return ; //如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并,直接返回;否则,执行下面的逻辑
if(rank[x]>rank[y]) pre[y]=x; //如果 x的高度大于 y,则令 y的上级为 x
else //否则
{
if(rank[x]==rank[y]) rank[y]++; //如果 x的高度和 y的高度相同,则令 y的高度加1
pre[x]=y; //让 x的上级为 y
}
}
————————————————
版权声明:本文为CSDN博主「酱懵静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/the_ZED/article/details/105126583
2. 带权的。
可以用于判断最小环和其他想不到 的问题
int find(int k)
{
if(k!=f[k])
{
int t=f[k];
f[k]=find(f[k]);
value[k]+=value[t];
}
return f[k];
}
void Union(int a,int b){
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
f[fa]=fb;
value[fa]=-value[a]+value[b]+(a到b的权值);
}
}
P2661 [NOIP2015 提高组] 信息传递 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P6691 选择题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
5. 逆向思维
并查集无法实现拆分。
所以当我们需要拆路去处理并查集相关的问题(连通块,集合个数等)时,我们可以反向操作。用一个数组去存差点(路)的顺序(离线操作),然后当我们反向去处理问题的时候,就变成了合并。
一般与图论相关的知识有关。
因为要离线操作,我们就需要存图,存数据。
P6121 [USACO16OPEN]Closing the Farm G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
6. 特殊点
特殊点与集合的关系
1. 求集合中同时有两个点的个数
当满足条件时,用新的 f[] 记录。
P3958 [NOIP2017 提高组] 奶酪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
7. 种类
P1892 [BOI2003]团伙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
并查集不难用,在题目怎么看出来才难。
学的太慢。
应该先把题目和题解都看完,再去敲。
先总整体上把控一下一个知识点有几种题型,再想一下难易程度,然后按照难易分配不同的时间去做题。
心态太容易炸了,每次遇到不会的题就开始摆烂,不去耐着心思继续读题。眼高手低,每次都想成为最好的,一有错就想等下次比赛从新来过。殊不知,没有失败就不会有成功。
费老师说搞他这个就把其他的都放下,确实,我心里撑不住事情,一有事就会去想,担心那件事如何如何的,但是我不敢把其他的东西放下,太怂了,不想没有退路,更多的是没有信心能把事情做好。其实现在啥都弄好,看他们有,就想要,却又付出不了那种汗水。
讲真的,学习算法的时候,每次看懂一个知识点,是很开心的。但看到别人弄个小游戏,写个爬虫,做个网页也挺羡慕的,就是太贪心了。
每次事情一多,我首先不是想如何去解决,而是去逃避,拿手机看一会,去睡一会觉,去洗个澡,发个呆。
需要回扣总结的东西有很多,但是一直懒得总结,总给自己找没有时间的理由。
上学期acm协会的宣传的时候,了解到了算法,感觉很酷很好玩。当时就跟着做了一下洛谷提单前面几个简单的模块,但也因为一些其他的事没有坚持下来。新生赛时,看到有很多人能把自己看都看不懂的题a出来,当时还以为他们高中的时候就学过,现在才知道,他们是上了大学才开始学的。问过第一名怎么学的,他舍友说,他就是做题,哪里不会,就去搜资料,然后去学习。这一点和费老师说的一样,我一直认为这样学的不系统,感觉长期以往的话,会不扎实,现在看来,是我错了,更主要的是我没有他那种专注。去过他宿舍,他遇到不会的东西就去学,不会管其他的,心无旁骛。每次周围有人说什么话,我都会受别人说的话影响。再后来,想要跟着费老师学习,然后想去打个比赛,只是因为喜欢。高中过的太混了,大学不想混了。上学期问了很多关于算法课的问题。当选课时,发现我的课和费老师的课冲突的时候,报不上了,感觉心里空荡荡的。最后几经周折,好不容易报上了,但经过那种就是,颓废,然后落下作业,看到别人的进步,没有激励到我,反而是嫉妒,每次都忽略别人的付出。现在课快结束了,初心也快忘了。
大一嘛,每个人想去尝试一些新鲜的东西。之前一起上算法课的同学,很多都报了其他的东西,我也是。但他们现在都,都退了,他们敢孤注一掷的勇气,是我羡慕,但做不来的。有些人可以同时可以干很多事,我以为我也是,可惜并不是如此。我不知道我该去做什么,我想去寻找最优解,但最优解一定不是现在。
我以为我够认真了,只是效率不高,结果今天才发现,一块上课的同学,一直都比我起的早,回来的晚。拼效率拼不过,现在拼时间也拼不过。
想以后跟着费老师继续搞下去,之前是,现在也是,但现在的状态肯定是不可以的。
时间不多了。
---------------------------------------------------------------------------------------------------------
睡不着,在床上想结课后,我的总结会怎么去写呢。不能留下遗憾。