最小生成树
1.kruskal(克鲁斯卡尔)算法
将所有边由小到大排序,依次进行有效的扩展(即有一节点加入集合),直到已经形成一棵树,此时生成的树即为最小生成树
ps:需用并查集才更好
```
//洛谷1546
#include<cstdio>
#include<algorithm>
using namespace std;
int n,cnt,sum,ans;
int fa[105];
struct edg{
int from,to,dis;
}edge[10005];
bool cmp(edg x,edg y){
return x.dis<y.dis;
}
int find(int x) //查找根节点
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void join(int a,int b){
int x=find(a);
int y=find(b);
if(x!=y) fa[x]=y;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int x;
scanf("%d",&x);
if(i!=j){
cnt++;
edge[cnt].dis=x;
edge[cnt].from=i,edge[cnt].to=j;
}
}
for(int i=1;i<=n;i++) fa[i]=i;
sort(edge+1,edge+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
if(find(edge[i].from)!=find(edge[i].to)){
join(edge[i].from,edge[i].to);
sum+=edge[i].dis;
ans++;
}
if(ans==n-1) break;
}
printf("%d",sum);
return 0;
}
```
2.prim(普里姆)算法
每次选一个 与最小生成树相连的最小花费最少的节点 进入最小生成树,并用这个节点尝试更新它所连所有节点的 与最小生成树相连的最小花费(因为有节点进入,最小生成树发生改变),直到最终完成
```
//洛谷1265
#include<cstdio>
#include<cmath>
using namespace std;
int n,cnt;
double sum;
int mst[5005];
double dis[5005][5005],mincost[5005];
struct point{
int x,y;
}city[5005];
double qdis(int a,int b){
// if(dis[a][b]) return dis[a][b];
// else
// return dis[a][b]=dis[b][a]=sqrt(abs(city[a].x-city[b].x)*abs(city[a].x-city[b].x)+abs(city[a].y-city[b].y)*abs(city[a].y-city[b].y));
return sqrt(abs(city[a].x-city[b].x)*abs(city[a].x-city[b].x)+abs(city[a].y-city[b].y)*abs(city[a].y-city[b].y));
}
void prim(int t){//函数没写好 懒得改了 明白怎么回事就好
if(cnt==n-1) return ;
cnt++;
int k; double minn=0x3f3f3f3f;
for(register int i=1;i<=n;i++) {
if(!mst[i]&&mincost[i]<minn){
minn=mincost[i];
k=i;
}
}
mst[k]=1;
for(register int i=1;i<=n;i++)
if(!mst[i]&&qdis(i,k)<mincost[i])
mincost[i]=qdis(i,k);
sum+=minn;
prim(k);
return ;
}
int main(){
scanf("%d",&n);
for(register int i=1;i<=n;i++)
scanf("%d %d",&city[i].x,&city[i].y);
for(register int i=2;i<=n;i++) mincost[i]=qdis(i,1);
mst[1]=1;
prim(1);
printf("%.2f",sum);
return 0;
}
```
版权声明:本文为博主原创文章,未经博主允许不得转载。
博主:https://www.cnblogs.com/Menteur-Hxy/