首先是模板
并查集模板:
int pre[1000 ];
int find(int x) //查找根节点
{
int r=x;
while ( pre[r ] != r ) //返回根节点 r
r=pre[r ];
int i=x , j ;
while( i != r ) //路径压缩
{
j = pre[ i ]; // 在改变上级之前用临时变量 j 记录下他的值
pre[ i ]= r ; //把上级改为根节点
i=j;
}
return r ;
}
void join(int x,int y) //判断x y是否连通,
//如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,
{
int fx=find(x),fy=find(y);
if(fx!=fy)
pre[fx ]=fy;
}
KRUSCAL算法:
kruskal算法的精髓在于:
每次选取一条边。
该边同时满足:1、在当前未选边中权值最小;2、与已选边不构成回路。
直到选取n-1条表是算法结束。找到MST活判断不存在MST。
常用优先队列
贴代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<vector>
#include<algorithm>
using namespace std;
int n,father[510];
int a[510][510];
int find_ancestor(int x)
{
int r=x;
while(father[r]!=r)
r=father[r];//此时r为根节点
int i=x,j;
while(i!=r)
{
j=father[i];
father[i]=r;
i=j;
}
return r;//路径压缩,把所有的x的父节点的父节点都设置为祖先
}
void add_bian(int x,int y)
{
int fx=find_ancestor(x),fy=find_ancestor(y);
if(fx!=fy)
father[min(fx,fy)]=max(fx,fy);
}
int main(void)
{
int total,t,cnt,min_cost,min_i,min_j;
scanf("%d",&t);
while(t--)
{
total=cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
father[i]=i;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
while(cnt<n-1)
{
min_cost=INT_MAX;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
continue;
if((a[i][j]<min_cost)&&(find_ancestor(i)!=find_ancestor(j)))
{
min_i=i;
min_j=j;
min_cost=a[i][j];
}
}
add_bian(min_i,min_j);
cnt++;
total=max(total,a[min_i][min_j]);
}
printf("%d\n",total);
}
return 0;
return 0;
}