克鲁斯卡尔算法(Kruskal)

  1. 克鲁斯卡尔

模板题目:

 

 

 图中的6个顶点分别代表6个村庄,线段的权值代表村庄之间的距离。请问如何找到最短的路径来访问每一个村庄,且每个村庄只访问一次。

关键:

  1. 一个存储边的结构体(edgetype),包括起点(from)终点(to)权值(weight
  2. 一个存储树的结构体(edggragh),这棵树包含:边的个数(edgenum),顶点的个数(vesnum),包含顶点序号的数组(顶点数组:vesn[100]),边的结构体(edgen[100])
  3. 三个函数

(1)初始化inigragh

Step1:用一个结构体变量(Myedge)存储边的信息包括:顶点数(vexn),边数(edgen),每个边的权值。

Step2:把结构体变量(Myedge)按找权值(weight)进行排序(这里使用冒泡法排序)

Step3:把排好序的结构体变量(Myedge)汇入到树(Mygragh)中,并初始化树的顶点数组vesn[100])

(2) 构建生成树并输出waygragh

Step1:新建一个容器(mst)来存放新的生成树

Step2:新建一个数组(root)来存放每个节点的根,并把他初始化(-1),以表示在构建前,每个节点都是一棵独立的树,根节点为他本身

Step3:根据每条边的权值从小到大寻找每一条边的起始节和终点节点(因为在上一个函数中已经排好序,所以实际上是顺序查找),并判断起始节点和终点节点的根节点是否相同(是否能构成环),这一步需要引用寻找根节点的函数(soortfind)

Step4:如果不能构成环,就把这条边的数据放入容器mst

Step5:如果检查完了所有的边就跳出

Step6:输出mst

(3) 寻找根节点soortfind:

接收顶点的序号,借助于while寻找根,具体实现请看代码部分和注释

下面的代码有一点问题,在编译器中前几次运行数值不定,多运行几次后趋于稳定

 

复制代码
#include<bits/stdc++.h>
using namespace std;
struct edgetype//存储边的结构体 
{
    int from,to; 
    int weight;
};
struct edggragh//存储树的结构体 
{
    int vexs[100];
    struct edgetype edges[100];
    int vexnum,edgenum;
};
void inigragh(struct edggragh *Mygragh);//初始化 声明 
void waygragh(struct edggragh *Mygragh);//构建生成树并输出 声明 
int rootfind(int parent[],int v);//寻找根节点的 声明 
int main()//主函数只调用子函数 
{
    edggragh Myedge;
    inigragh(&Myedge);
    waygragh(&Myedge);
    system("pause");
    return 0;
}
//初始化
void inigragh(struct edggragh *Mygragh)
{
    int vexn;
    int edgen;
    cout<<"请输入顶点个数:";
    cin>>vexn;
    cout<<"请输入边的个数:";
    cin>>edgen;
    edgetype *Myedge=new edgetype[edgen];
    cout<<"请输入各个边的起点,终点和权值(用空格隔开):"<<endl;
    for(int i=0;i<edgen;i++) 
    {
        cin>>Myedge[i].from>>Myedge[i].to>>Myedge[i].weight;
    }
    for(int i=0;i<edgen;i++)//冒泡排序 
    for(int j=0;j<edgen-1-i;j++)
    {   edgetype temp;
        if(Myedge[j].weight>Myedge[j+1].weight)
        {
            temp=Myedge[j];
            Myedge[j]=Myedge[j+1];
            Myedge[j+1]=temp;
        }
     }
     (*Mygragh).vexnum=vexn;//对结构体变量(Myedge) 进行初始化 
     (*Mygragh).edgenum=edgen;
    for(int i=0;i<edgen;i++)
    {
        (*Mygragh).edges[i]=Myedge[i];
    }
    for(int i=0;i<vexn;i++)
    {
        (*Mygragh).vexs[i]=i;
    }
}
//构建生成树并输出
void waygragh(struct edggragh *Mygragh)
{    edgetype *mst=new edgetype[(*Mygragh).vexnum];//新建一个容器(mst)来存放新的生成树
     int *root=new int[(*Mygragh).vexnum];//新建一个数组(root)来存放每个节点的根
     for(int i=0;i<(*Mygragh).vexnum;i++)//初始化 
     {
         root[i]=-1;
     }
     int num=0;//控制mst容器的下标 
     for(int i=0;i<(*Mygragh).edgenum;i++)
     {  //引用soortfind函数寻找根节点 
        int v1=rootfind(root,(*Mygragh).edges[i].from); 
        int v2=rootfind(root,(*Mygragh).edges[i].to);
        // 如果不能构成环,就把这条边的数据放入容器mst中
        if(v1!=v2)
        {
            mst[num]=(*Mygragh).edges[i];
            root[v2]=v1;
            num++;
            
        }
        //如果检查完了所有的边就跳出 
        if(num==(*Mygragh).vexnum-1)
            break;
     } 
     //输出mst 
    for(int i=0;i<num;i++)
    {
        cout<<"("<<mst[i].from<<","<<mst[i].to<<")"<<mst[i].weight<<endl;
    }
} 
//寻找根节点
int rootfind(int parent[],int v)
     {
         int v1=v;
         while(parent[v1]>-1)
         v1=parent[v1];
         return v1;
     }
复制代码

 

正确的模板:

复制代码
void Kruskal(int n,int m)
{
int i,sum=0,ans=0;
for(i=1;i<=n;i++)
{
pre[i]=i;
}
for(i=1;i<=m;i++)
{
int x=root(s[i].u);
int y=root(s[i].v);
if(x!=y)
{
sum++;
ans+=s[i].w;
pre[x]=pre[y];
if(sum == n)
                break;
}
}
cout<<ans<<endl;
}
复制代码

例题:

http://10.64.27.5:8888/p/P32?tid=61eb7a0dc3d405e68f6392d7

ac代码:

复制代码
#include<bits/stdc++.h>
long long zu[1000];
long long m,n;
using namespace std;
struct node
{
    long long  s;
    long long  e;
    long long  w;
};
node edge[1000];
bool cmp(struct node x,struct node y)
{
    return x.w<y.w;
}
int root(long long a)
{
    int r=a;
    while(zu[r]!=r)
    {
        r=zu[r];
    }
    int b=a,c;
    while(zu[b]!=r)//减少运算量的步骤,把每个节点都指向它的根节点
    {
        c=zu[b];
        zu[b]=r;
        b=c;
    }
    return r;
}
void kkk(long long  m,long long  n)
{   node mst[100];
    long long i,count=0;
    long long ans=0;
    for(i=0;i<n;i++)
    {
        int v1=root(edge[i].s);
        int v2=root(edge[i].e);
        if(v1!=v2)
        {
            mst[count]=edge[i];
            count++;
            ans+=edge[i].w;
            zu[v1]=v2;
        }
        if(count==m)
        break;
    }
    for(int i=0;i<count;i++)
    cout<<mst[i].s<<mst[i].e<<mst[i].w<<endl;
    cout<<ans<<endl;
}
int main()
{
    cin>>m>>n;
    for(int i=0;i<n;i++)
    {
        cin>>edge[i].s>>edge[i].e>>edge[i].w;
    }
    for(int i=0;i<m;i++)
    {
        zu[i]=i;
    }
    sort(edge,edge+n+1,cmp);//取决于边数
    kkk(m,n);
    return 0;
}
复制代码

简单的对以前在word中的算法笔记进行整理,自用,参考标注不完整,侵删

 

posted @   格蕾  阅读(333)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示