Kruskal算法的步骤包括:
1. 对所有权值进行从小到大排序(这里对边排序时还需要记录边的索引,这样以边的权值排完序后只改变了权值的索引位置)
2. 然后每次选取最小的权值,如果和已有点集构成环则跳过,否则加到该点集中。最终有所有的点集构成的树就是最佳的。
#include <cstdio>
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define maxn 100010
using namespace std;
int n;
int a;
struct edge
{
int u;
int v;
int w;
};
struct edge e[maxn];
int f[101]={0},sum=0;
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
int find(int x)
{
if(f[x]==x) return x;
else
{
f[x]=find(f[x]);
return f[x];
}
}
int merge(int v,int u)
{
int t1=find(v);
int t2=find(u);
if(t1!=t2)
{
f[t2]=t1;
return 1;
}
return 0;
}
int main()
{
scanf("%d",&n);
int cnt;
int count;
for(int i=1;i<=n;i++)
{
f[i]=i;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a);
if(i==j) continue;
e[++cnt].u=i;
e[cnt].v=j;
e[cnt].w=a;
}
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=cnt;i++)
{
if(find(e[i].u)!=find(e[i].v))
{
if(merge(e[i].u,e[i].v))
{
count++;
sum+=e[i].w;
}
if(count==n-1)
{
break;
}
}
}
printf("%d",sum);
return 0;
}
Prim算法的步骤包括:
1. 将一个图分为两部分,一部分归为点集U,一部分归为点集V,U的初始集合为{V1},V的初始集合为{ALL-V1}。
2. 针对U开始找U中各节点的所有关联的边的权值最小的那个,然后将关联的节点Vi加入到U中,并且从V中删除(注意不能形成环)。
3. 递归执行步骤2,直到V中的集合为空。
4. U中所有节点构成的树就是最小生成树。
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=110;
int e[maxn][maxn],dis[maxn];
bool b[maxn];
int ans=0;
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>e[i][j];
}
}
int u,minn;
for(int i=1;i<=n;i++)
{
b[i]=false;
}b[1]=true;
for(int i=1;i<=n;i++)
{
dis[i]=e[1][i];
}
for(int i=1;i<=n;i++)
{
minn=1e9;
for(int j=1;j<=n;j++)
{
if(b[j]==false&&minn>dis[j])
{
minn=dis[j];
u=j;
}
}
if(minn==1e9) break;
ans+=minn;
b[u]=true;
for(int v=1;v<=n;v++)
{
if(b[v]==false&&dis[v]>e[u][v])
{
dis[v]=e[u][v];
}
}
}
cout<<ans<<endl;
return 0;
}