好久没更文章了,不写笔记又开始心浮气躁了。
五一给自己放了八天假,在珠三角和男票玩的不亦乐乎,假期后就火葬场了~
咨询了一个去年成绩很好的学长,保外失败的原因是机试没pass,且夏令营竞争激烈,没有参加预推免等等。
据说机试题一年比一年难,虽说出了个读研去机试的政策,但还是先刷为敬。
然后再看看论文、做做项目吧,指望别人是指望不上了~还是要自己动手总结才学的明白呀。
Introduction
图论问题中常用的一种数据结构就是并查集(Union Find),用于处理不交集(Disjoint Sets)的合并和查询问题。
并查集有两个功能:
- 判断任意两个元素是否属于同一个集合
- 按照要求合并不同的集合
并查集的特点:
- 表示为树结构,每个结点都指向其父结点,在同一棵树上便属于同一个集合(如何判断同一棵树?不断向上查找 Find,根节点相同便是同一棵树)
- 合并 Union 时,将矮树作为高树子树合并(高树高度+1即可),尽量保持较低的树高(合并时矮树根节点指向高树根节点)
Sample
假设有4个城镇(结点),2条道路(2次合并操作)
道路分别连接
0 2
3 2 城市
最少还需要建设几条道路?
代码:
void Initial(int n){
for(int i = 0; i <= n; ++i{
father[i] = i; // 初始化:每个结点的父亲为自己
height[i] = 0; // 高度为0
}
}
- 初始化:每个结点的父亲为自己,高度为0
int Find(int x){
if(x != father[x]){ // 结点index和父节点相等的结点为根节点,不相等的就递归查找
// 该结点的根节点等于父节点的父节点~ 一直往上找
father[x] = Find(father[x]);
}
// 如果是根节点,直接返回
return father[x];
}
void Union(int x, int y){
x = Find(x);
y = Find(y); // step 1: 找根节点
if(x != y){
if(height[x] < height[y]){
father[x] = y;
}else if(height[y] < height[x]){
father[y] = x; // step 2: 矮树作为高树的子树(矮树的fahter为高树index),高树高度不变
}else{
fahter[y] = x;
height[x]++; // step 3: 当height相等时,一棵树嫁接到另一棵树的根节点上,所以高度仅+1~
}
}
return ;
}
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1000;
int father[MAXN];
int height[MAXN];
int main(){
int n, m;
while(scanf("%d", &n) != EOF){
if(n == 0){
break;
}
scanf("%d", &m);
Initial(n);
while(m--){
int x, y;
scanf("%d %d", &x, &y);
Union(x, y);
}
int answer = -1;
for(int i = 1; i <= n; i++){
if(Find(i) == i){
answer++; // 这里题干的集合结点从1开始count~ 所以这样
// count的是集合的数量,所以所需要再建的桥的数量为集合-1,故answer从-1开始~
}
}
}
return 0;
}
Source
浙江大学复试上机题
solution
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1000;
int father[MAXN];
int height[MAXN];
// 初始化结点属性:父亲、高度
void Initial(int n){
for(int i = 0; i <= n; i++){
father[i] = i;
height[i] = 0;
}
}
// 递归查找根节点
int Find(int x){
if(x != father[x]){
father[x] = Find(father[x]);
}
return father[x];
}
// 矮树作为高树子树or相同高度合并且高度+1or根节点相同不做操作
void Union(int x, int y){
x = Find(x);
y = Find(y);
if(x != y){
if(height[x] < height[y]){
father[x] = y;
}else if(height[y] < height[x]){
father[y] = x;
}else{
father[y] = x;
height[x]++;
}
}
return ;
}
int main(){
int n, m;
while(scanf("%d", &n) != EOF){
if(n == 0){
break;
}
scanf("%d", &m);
Initial(n);
while(m--){
int x, y;
scanf("%d", &x);
scanf("%d", &y);
Union(x, y);
}
// 查找所有集合(父亲结点等于自身index的结点为根节点)
// 连接数等于结点数-1,answer初始化为-1
int answer = -1;
for(int i = 1; i <= n; ++i){
if(Find(i) == i){
answer++;
}
}
printf("%d\n", answer);
}
return 0;
}