• Kruakal 算法——练习总结


    在用Kruskal算法做最小生成树的时候,一般会包含:一个结构体edge(用于记录边的起点、终点、权值);一个UFset()函数(用于初始化每个节点的parent[]数组);一个Find(int x)函数(用于找x节点所在树的根节点,并通过并查集对查找路径进行压缩);一个Union(int R1,int R2)函数(用于把两个不在同一棵树的节点合并到一起);cmp函数(排序用到);Kruskal()函数(用于找到最优解);主函数(主要是做输入和输出操作,也可以分出来写)。

    在解决大部分最小生成树问题的时候UFset、Find、Union这些函数几乎不用修改。大多数题目是在程序的输入部分做文章,只要把题目的输入格式转化成通用的就好了(即:获得每条边的顶点(用数字表示)和权值),如果需要输出选取的路径(边),则要在Kruskal()中注意保存选择的路径。

    下面给出一些示例:

    UFset函数:

    void UFset()
    {
    for(i=0; i<N; i++)
    {
    parent[i]=-1;
    }
    }

    Find函数:

    int Find(int x)
    {
    int s;
    for(s=x; parent[s]>0;s=parent[s]);
    while(s!=x)
    {
    int tmp=parent[x];
    parent[x]=s;
    x=tmp;
    }
    return s;
    }

    Union函数:

    void Union(int R1,int R2)
    {
    int r1=Find(R1);
    int r2=Find(R2);
    int tmp=parent[r1]+parent[r2];
    if(parent[r1]<parent[r2])
    {
    parent[r2]=r1;
    parent[r1]=tmp;
    }
    else
    {
    parent[r1]=r2;
    parent[r2]=tmp;
    }
    }

    cmp

    int cmp(const void *a,const void *b)
    {
    edge aa=*(const edge *)a;
    edge bb=*(const edge *)b;
    if(aa.w>bb.w)
    return 1;
    else return -1;
    }

    这些几乎是不需要怎么变得。

    Kruskal函数

    (1)输出最短路径长度、最小费用的

    void Kruskal()
    {
    int num=0;//已选用的边的数目
    int u,v;//已选用边的两个顶点
    UFset();

    for(i=0;i<M;i++)
    {
    u=edges[i].u;
    v=edges[i].v;
    if(Find(u)!= Find(v))
    {
    sumweight+=edges[i].w;
    num++;

    Union(u,v);

    }
    if(num==N-1)break;//N个顶点N-1条边可以保证连通

    }
    }

    (2)需要把选择的路径输出出来

    void Kruskal()
    {
    ai=0;//数组ans的下标
    int u,v;
    UFset();

    for(i=0; i<M; i++)
    {
    u=edges[i].u;
    v=edges[i].v;
    if(Find(u)!=Find(v))
    {
    ans[ai]=i;ai++;//ans数组用于记录依次输出的边(即选择的路径)的序号,ai为ans的下标
    if(edges[i].w>maxedge)
    {
    maxedge=edges[i].w;
    }
    num++;
    Union(u,v);
    }
    if(num>=N-1)break;
    }
    }

    一些输入形式

    (最简单的,不需转换)

    for(i=0; i<M; i++)
    {
    scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].w);
    }

    (节点是字母)

    for(i=0; i<N-1; i++)
    {
    getchar();
    scanf("%c",&c);
    scanf("%d",&numm);
    for(j=0;j<numm;j++)
    {
    getchar();
    scanf("%c %d",&cc,&edges[mi].w);
    edges[mi].u=c-'A'+1;//把字母转换成数字的形式
    edges[mi].v=cc-'A'+1;//同上
    //printf("%d %d ",edges[mi].u,edges[mi].v);
    mi++;
    }
    }

    (节点是坐标)

    for(i=0;i<N; i++)
    {
    scanf("%lf%lf",&X[i],&Y[i]);
    }
    int mi=0;//边的序号,并且用于记录总共有多少条边
    for(i=0; i<N; i++)
    {
    for(j=i+1; j<N; j++)
    {
    d=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));//获得边的权值
    edges[mi].u=i;edges[mi].v=j;edges[mi].w=d;
    mi++;
    }
    }
    m=mi;

    转载请注明:http://www.cnblogs.com/ACshasow/

  • 相关阅读:
    vue-cli3中热更新失效,修改完代码之后需要手动刷新页面才能看到改变,解决办法
    数组中的数据项包含逗号则需在首尾拼接中括号[]来区分每一项,最后数组转为字符串,以及数据恢复
    组件之间的拖拽
    工作心得
    Vue重点知识
    vue-router路由
    利用注解和反射,将Bean枚举字段的值填入相应的字段中,并转化为fastjson返回前台
    db2 获取自增主键的方法
    mybatis注解@selectKey对于db2数据库的使用
    @InsertProvider 根据bean属性,自动生成插入sql语句
  • 原文地址:https://www.cnblogs.com/ACshasow/p/3243469.html
Copyright © 2020-2023  润新知