创建最小生成树
Prim算法
- Prim算法基本概念:
以点为基础创建最小生成树此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。 - Prim算法原理图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200602192010895.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3l6eTI1OA==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200602192017383.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3l6eTI1OA==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200602192031539.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3l6eTI1OA==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020060219204248.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3l6eTI1OA==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020060219205769.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3l6eTI1OA==,size_16,color_FFFFFF,t_70)
- Prim算法代码粗解(表达没有很准确)
第一步先构造一个邻接矩阵图,并取出第一个节点的各各边放入一个dist[]数组中,之后循环取出dist[]数组中最小的值就可以找到下一个该连的结点,并将执行过的结点标记为0,然后遍历第二个节点的的各各边的权重与dist[]中的值进行比较,如果小于他则替换他,以此循环,最后判断如果dist[]中的所有值都为0则表示生成树构建成功。 - Prim算法代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int side,drop;
int graph[1000][10000];
int dist[1000]={99999};
int a,b,c;
int countt=0;
void Prim(int x,int y)
{
for(int i=1;i<=x;i++){
for(int j=1;j<=x;j++){
graph[i][j]=99999;
}
}
for(int i=1;i<=y;i++){
cin>>a>>b>>c;
graph[a][b]=c;
graph[b][a]=c;
}
for(int i=1;i<=x;i++){
dist[i]=graph[1][i];
}
dist[1]=0;
cout<<"1"<<"-->";
while(1){
int v=0;
for(int i=1;i<=x;i++){
if(dist[i]<dist[v]&&dist[i]){
v=i;
}
}
if(v!=0){
cout<<v<<"-->";
}
if(!v){break;}
countt=countt+dist[v];
dist[v]=0;
for(int i=1;i<=x;i++){
if(graph[v][i]<dist[i]){
dist[i]=graph[v][i];
}
}
}
bool flag=true;
for(int i=1;i<=x;i++){
if(dist[i]){
flag=false;
}
}
if(flag){
cout<<"存在最小生成树"<<countt;
}else{
cout<<"不存在最小生成树";
}
}
int main()
{
cin>>side>>drop;
Prim(side,drop);
return 0;
}
Kruskal算法
- Kruskal的基本概念
算法是构建最小生成树的另一个算法,其是对边进行操作,来构建最小生成树的。第一步:把所有的边按权值从小到大排列。第二步:按照顺序选取每条边,如果这条边的两个端点不属于同一集合,那么就将它们合并。重复第二步,直到 所有的点都属于同一个集合。步骤实施与prim算法异曲同工就不在放图。 - Kruskal算法代码粗解(表达没有很准确)
简单来说就是一个并查集的方法,找到那些点的直接或间接父亲结点并将其赋值,其值与父亲结点一致,以示两,者之间的关系。如果输入的两条边对应的值都相同说明两者已经存在关系,再添入则会照成环路导致最小生成树不成立 - Kruskal算法代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int side,drop;
int fat[200010];
int k=0;
int sum=0;
struct node{
int from;
int to;
int weight;
}edge[200010];
bool cmp(const node &a,const node &b)
{
return a.weight<b.weight;
}
int father(int x)
{
if(fat[x]!=x){
return father(fat[x]);
}
else{
return x;
}
}
void unionn(int x,int y)
{
fat[father(y)]=father(x);
}
void Kruskal(int x,int y)
{
for(int i=1;i<=y;i++){
fat[i]=i;
}
for(int i=1;i<=y;i++){
cin>>edge[i].from>>edge[i].to>>edge[i].weight;
}
sort(edge+1,edge+y+1,cmp);
for(int i=1;i<=y;i++){
if(k==x-1){break;}
if(father(edge[i].from)!=father(edge[i].to)){
unionn(edge[i].from,edge[i].to);
cout<<edge[i].from<<"-->"<<edge[i].to<<" ";
sum+=edge[i].weight;
k++;
}
}
if(k==x-1){
cout<<"\n"<<"存在最小树"<<sum;
}else{
cout<<"最小树不存在";
}
}
int main()
{
cin>>side>>drop;
Kruskal(side,drop);
return 0;
}