标签:树形结构 The lang 建立 lse tin 递归 turn 压缩
1. 构建一个无向图,同一个团体加同样的标记,合并时复杂度很高,查询为O(1)
2. 并查集,树形结构的数组(不相交集合的合并,查询等问题):建立集合,查询元素所在集合,合并集合...
初始化:f(i) = i
const int kN = 1010;
int x,f[kN];
//加权并查集特殊处理,关系间存在权值,有顺序,不可路径压缩,另外一个数组存储权值
//路径压缩 f[kid] = f[father],减少查询时的复杂度,所有子节点均指向代表元素
//不使用路径压缩,最坏情况下会退化为一个链表
//初始化 自己代表自己
void init(){
for(int i = 1; i <= n; i++) f[i] = i;
}
//查找集合的代表元素 root,查找过程中进行路径压缩
int find(int x){
//当前节点 - 父节点 -> 找到root
//非递归
int r = x,t;
while(r != f[r]){//寻找代表元素
r = f[r];
}
while(x != r){
t = f[x];
f[x] = r;
x = t;
}
return r;
//递归,速度较慢
if(f[x] != x) f[x] = find(f[x]);
else return f[x];
}
//判断两元素是否为同一集合
bool judge(int x,int y){
if(find(x) == find(y)) return true;
return false;
}
//集合合并,修改代表元素指向即可
//合并方法二:按秩合并,深度小的树合并到深度大的树,深度小的树的root指向深度大的树的root,防止退化
void unionn(int x,int y){
x = find(x);
y = find(y);
f[x] = y;
}
//x加入y所在的集合
void join(int x,int y){
int rx = find(x),ry = find(y);
if(rx != ry) f[rx] = ry;
}
const int kN = 1010;
int n,m,x,s,e,ans,f[kN];
map<int,bool> book;
//初始化 自己代表自己
void init(){
for(int i = 1; i <= n; i++) f[i] = i;
}
//查找集合的代表元素 root,查找过程中进行路径压缩
int find(int x){
//当前节点 - 父节点 -> 找到root
//非递归
int r = x,t;
while(r != f[r]){//寻找代表元素
r = f[r];
}
while(x != r){
t = f[x];
f[x] = r;
x = t;
}
return r;
}
//x加入y所在的集合
void join(int x,int y){
int rx = find(x),ry = find(y);
if(rx != ry) f[rx] = ry;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
while(cin >> n){
if(!n) break;
cin >> m;
init();
for(int i = 0; i < m; i++){
cin >> s >> e;
join(s,e);
}
book.clear();
for(int i = 1; i <= n; i++) book[find(i)] = true;
cout << book.size() - 1 << endl;
}
return 0;
}
(无向图)最小生成树de两种贪心算法
kruskal算法:并查集判断成环,边权升序排列,从前到后枚举,当这条边加入后不成环则可加入。
? n个节点的连通图找到n-1条边,使所有节点都可到达,且这些边的权值和最小。
int x,f[kN];
struct edge{
int form,to,value;
}
int kruskal(edge *edges,int m){//边集 大小
sort(edges,edges + m,cmp);//按边权升序排列
int r = 0;//权
for(int i = 0; i < m; i++){
if(find(deges[i].from) == find(edges[i].to)) continue;//成环,在同一连通块中
r += edges[i].value;//边权加入权值和
unionn(edges[i].from,edges[i].to);//合并连通块
}
return r;
}
prim算法:
int edges[N][N],dist[N];
bool vis[N];
void add_edge(int form,int to,int value){
edges[form][to] = max(edges[from][to],value);
edges[to][form] = max(edgee[to][form],value);
}
void init(){
memset(edges, - 1, sizeof(edges));
memset(dist, - 1, sizeof(dist));
memset(vis, false, sizeof(vis));
}
int prim(int n){
vis[1] = true;//任一节点开始
for(int i = 2; i <= n; i++) dist[i] = edges[1][i];
int ret = 0;
for(int i = 2; i <= n; i++){
int x = 1;
for(int j = 1; j <= n; j++){//寻找最小权值
if(!vis[j] && dist[j] > dist[x]) x = j;
}
ret += dist[x];
vis[x] = true;
for(int j = 1; j <= n; j++){//更新dist x -> 其他节点
if(!vis[j]) dist[j] = max(dist[j],edges[x][j]);
}
}
return ret;
}
标签:树形结构 The lang 建立 lse tin 递归 turn 压缩
原文地址:https://www.cnblogs.com/honey-cat/p/12751209.html