最小生成树的简易实现
一:Kruskal 算法
①算法核心思想:
Kruskal是实现最小生成树比较简单的一种算法。该算法主要是应用了并查集的思想,先对图各边进行按权值从小到大排序,再孤立各个点,然后按序遍历各边将在集合外的点并到集合里,形成一个最小生成树复杂度最少为O(nlogn)。
②例题P2504聪明的猴子
AC代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y;
int len;
}w[1000009];
int pre[1000009];
int bloon[1000009];
int wood[1000009][3];
int find(int x){
if(x==pre[x]){
return x;
}
return pre[x]=find(pre[x]);//路径压缩算法
}
int cmp(node a,node b){
return a.len<b.len;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;++i){
cin>>bloon[i];
}
int m;
cin>>m;
for(int i=1;i<=m;++i){
cin>>wood[i][1]>>wood[i][2];
}
int k=0;
for(int i=1;i<=m;++i){
for(int j=1;j<=m;++j){
if(i!=j){
w[++k].x=i;
w[k].y=j;
w[k].len=sqrt((wood[i][1]-wood[j][1])*(wood[i][1]-wood[j][1])+(wood[i][2]-wood[j][2])*(wood[i][2]-wood[j][2]));
}
}
}
for(int i=1;i<=m;++i){
pre[i]=i;//孤立各点
}
sort(w+1,w+k+1,cmp);//自定义一个cmp排序函数
int length;
int cnt=m;
for(int i=1;i<=k;++i){
if(cnt==1)break;
int s1=find(w[i].x);int s2=find(w[i].y);
if(s1!=s2){
cnt--;
pre[s1]=s2;
length=w[i].len;
}
}
int ans=0;
for(int i=1;i<=n;++i){
if(bloon[i]>=length)ans++;
}
cout<<ans<<endl;
return 0;
}
二:Prim算法
①算法核心思想:
个人认为Prim算法会对初学者更友好一点,因为它是直接并和各点。首先把各点的距离设为无限大,把各点标记为零,然后遍历各点,找到与标记为一的点距离最近的点,然后更新该点标记为一,把其他“零点”到“一点”的距离更新为最短距离,算法复杂度O(n^2+m)。
②例题#2419繁忙的都市
AC代码:
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int st[1009][1009];
int main()
{
int n,m;
cin>>m>>n;
int x,y;
for(int i=1;i<=n;++i){
cin>>x>>y;
cin>>st[x][y];
st[y][x]=st[x][y];
}
int p[1009]={0};
int v[1009];
memset(v,0x7f,sizeof(v));
v[1]=0;
int maxv=0;
for(int i=1;i<=m;++i){
int k=0;
int j;
for(j=1;j<=m;++j){
if(!p[j]&&v[k]>v[j])k=j;
}
p[k]=1;
maxv=max(maxv,v[k]);
for(j=1;j<=m;++j){
if(!p[j]&&st[j][k]<v[j]&&st[j][k]!=0)v[j]=st[j][k];
}
}
cout<<m-1<<" "<<maxv<<endl;
return 0;
}