并查集(带路径压缩)
并查集
用于快速查找集合中元素是否存在关系的数据结构,主要操作为:查询和合并
并查集简述
常用的带有路径压缩版本的并查集模板:
带路径压缩的并查集在一般情况下的查询或者合并操作,其时间复杂度近似于O(1)
#define MAXN 5000
int fa[MAXN+1];
void init(int n)
{
for(int i = 1; i <= n; i++)
{
fa[i] = i; //初始化
}
}
int find(int x)
{
if(fa[x]==x)
return x;
return fa[x] = find(fa[x]); //查询时进行路径压缩
}
void merge(int x, int y)
{
fa[find(x)] = find(y); //合并
}
实战1:P1111修复公路
思路:这题本质要求我们权为时间t的图的最小生成树,具体做法为:先将边按时间从小到大排序,然后依次判断取边,当构成生成树(下为ans==n-1)时即输出答案即可
赋AC代码:
#include <stdio.h>
#include <stdlib.h>
#define MAXN 1000
int fa[MAXN+1];
typedef struct maye
{
int u, v, t;
}ccc;
void init(int n)
{
for(int i = 1; i <= n; i++)
{
fa[i] = i; //初始化
}
}
int find(int x)
{
if(fa[x]==x)
return x;
return fa[x] = find(fa[x]); //查询时进行路径压缩
}
void merge(int x, int y)
{
fa[find(x)] = find(y); //合并
}
int com(const void *a, const void *b)
{
return (*(ccc *)a).t - (*(ccc *)b).t;
}
int main(void)
{
int n, m, ans = 0;
scanf("%d %d",&n,&m);
init(n);
ccc path[m+1];
for(int i = 1; i <= m; i++)
{
scanf("%d %d %d",&path[i].u,&path[i].v,&path[i].t);
}
qsort(path+1, m, sizeof(ccc), com);
for(int i = 1; i <= m; i++)
{
if(find(path[i].u)!=find(path[i].v))
ans++;
merge(path[i].u, path[i].v);
if(ans==n-1)
{
printf("%d\n",path[i].t);
return 0;
}
}
printf("-1\n");
return 0;
}
实战2:P1195口袋的天空
思路:与上一题类似,同样将边按权从小到大排序,初始集合总数为n,然后对于每一条边,如果不连通,就选上并更新连通性(如果不用选就直接跳过),这样集合总数会-1,直到集合数为k时得到答案
赋AC代码:
#include <stdio.h>
#include <stdlib.h>
#define MAXN 1000
int fa[MAXN+1];
typedef struct maye
{
int u, v, l;
}ccc;
void init(int n)
{
for(int i = 1; i <= n; i++)
{
fa[i] = i; //初始化
}
}
int find(int x)
{
if(fa[x]==x)
return x;
return fa[x] = find(fa[x]); //查询时进行路径压缩
}
void merge(int x, int y)
{
fa[find(x)] = find(y); //合并
}
int com(const void *a, const void *b)
{
return (*(ccc *)a).l - (*(ccc *)b).l;
}
int main(void)
{
int n, m, ans, k, answer = 0;
scanf("%d %d %d",&n,&m,&k);
ans = n;
init(n);
ccc path[m+1];
for(int i = 1; i <= m; i++)
{
scanf("%d %d %d",&path[i].u,&path[i].v,&path[i].l);
}
qsort(path+1, m, sizeof(ccc), com);
for(int i = 1; i <= m; i++)
{
if(find(path[i].u)==find(path[i].v))
continue;
merge(path[i].u, path[i].v);
ans--;
answer+=path[i].l;
if(ans==k)
{
printf("%d\n",answer);
return 0;
}
}
printf("No Answer\n");
return 0;
}