一、kruskal算法
1、原理:在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边(加边法)。
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int u,v,w;
};
struct Edge e[50];
int a[50];
int n,m;
void quick_sort(int l,int r)
{
int i=l,j=r;
struct Edge tp;
if(l>r) return ;
while(i!=j) //先右后左
{
while(e[j].w>=e[l].w&&i<j) j--;
while(e[i].w<=e[l].w&&i<j) i++;
if(i<j)
{
tp=e[i];
e[i]=e[j];
e[j]=tp;
}
}
tp=e[l];
e[l]=e[i];
e[i]=tp;
quick_sort(l,i-1);
quick_sort(i+1,r);
return ;
}
int f(int x)
{
if(x==a[x]) return x;
else
{
a[x]=f(a[x]); //路径压缩
return a[x];
}
}
int Merge(int x,int y)
{
int t1=f(x);
int t2=f(y);
if(t1!=t2)
{
a[t2]=t1;
return 1;
}
return 0;
}
int main(void)
{
int i,j;
scanf("%d %d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
quick_sort(1,m); //按权值大小排好
for(i=1;i<=n;i++) a[i]=i; //初始化n个节点的数组
int cnt=0,sum=0;
for(i=1;i<=m;i++)
{
if(Merge(e[i].u,e[i].v)) //判断是否是回路
{
cnt++;
sum+=e[i].w;
}
if(cnt==n-1) break;
}
printf("%d\n",sum);
return 0;
}
/*输入数据:
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
输出数据:
19
*/
二、Prim算法
1、原理:从一个点开始每次找这个点的最小的边,直到找完n个点(加点法)
#include<bits/stdc++.h>
using namespace std;
int e[101][101],vis[101],dis[101];
const int INF=9999999;
int main(void)
{
int n,m,i,j;
scanf("%d %d",&n,&m);
//初始化
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=INF;
}
int t1,t2,t3;
//数据输入
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
e[t2][t1]=t3;
}
for(i=1;i<=n;i++)
{
dis[i]=e[1][i];
}
int cnt=1,sum=0;
vis[1]=1;
//prim核心,类似dijkstra
while(cnt<n)
{
int mi=INF,p;
for(i=1;i<=n;i++)
{
if(vis[i]==0&&mi>dis[i])
{
mi=dis[i];
p=i;
}
}
vis[p]=1;
sum+=dis[p];
cnt++;
for(i=1;i<=n;i++)
{
if(vis[i]==0&&dis[i]>e[p][i])
{
dis[i]=e[p][i];
}
}
}
printf("%d\n",sum);
return 0;
}
/*输入数据:
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
输出数据:
19
*/