• 图论算法-最小生成树


    图论算法-最小生成树

    在一个无向图中找出一颗最小生成树(minimum spanning tree),这个问题对有向图也是有意义的,不过找起来更困难。最小生成树存在当且仅当图GG是连通的。在最小生成树中边的条数为V1left | V ight |-1

    Prim算法

    在每一步,都要把一个节点当作根并往上边加。在算法的任一时刻,我们都可以看到一个已经添加到树上的顶点集,而其余顶点尚未加到这棵树中,此时,算法在每一阶段都可以通过选择边(u,v)(u,v),使得(u,v)(u,v)的值是所有uu在树上但vv不在树上的边值中的最小者,而找出一个新的顶点并把它添加到这棵树中。

    代码

    这里使用的邻接矩阵。

    void Prim(Graph g)
    {
        VertexType adjver[VERNUM];
        WeightType lowcost[VERNUM];
        int i, j, k;
        WeightType min;
    
        // 初始化,一开始生产树中只有开始的顶点
        // 这里开始的顶点的编号为 0
        for (i = 0; i < g->vernum; i++)
        {
            lowcost[i] = g->arc[0][i];
            adjver[i] = 0;
        }
    
        for (i = 1; i < g->vernum; i++)
        {
            // 在已生成树的顶点中查找权值最小的邻接点的边
            k = 0;
            min = INFINITY;
            for (j = 1; j < g->vernum; j++)
                if (lowcost[j] != 0 && lowcost[j] < min)
                {
                    min = lowcost[j];
                    k = j;
                }
    		
            // 输出新增加的顶点
            printf("(%d, %d)
    ", adjver[k] + 1, k + 1);
            lowcost[k] = 0;	// 标记添加到树中的顶点不再使用
    
            // 更新图中顶点邻接点的权值及顶点
            for (j = 1; j < g->vernum; j++)
                if (lowcost[j] != 0 && g->arc[k][j] < lowcost[j])
                {
                    adjver[j] = k;
                    lowcost[j] = g->arc[k][j];
                }
        }
    }
    

    输入/输出

    Input vernum: 7
    Input arcnum: 12
    1 2 2
    1 3 4
    1 4 1
    2 4 3
    2 5 10
    3 4 2
    3 6 5
    4 5 7
    4 6 8
    4 7 4
    5 7 6
    6 7 1
    Prim's algorithm minmum spanning tree:
    (1, 4)
    (1, 2)
    (4, 3)
    (4, 7)
    (7, 6)
    (7, 5)
    请按任意键继续. . .
    

    Kruskal算法

    第二种贪婪策略是连续地按照最小边的权选择边,并且当所选的边不产生圈时就把它作为取定的边。

    代码1

    图使用邻接矩阵表示。

    void Kruskal(Graph G)
    {
        int i, vs1, vs2;
        VertexType v1, v2;
        // 辅助数组
        VertexType head;	// 边的始点
        VertexType tail;	// 边的终点
        ArcType lowcost;	// 边的权值
        int Vexset[VerNum];	// 实际上是一个并查集(不相交集)
        
        // 按图中的边的权值大小排序,存储到前三个数组中
       	Sort(Edge);	// 将前3个数组中的元素按权值从小到大排序
        for(i = 0; i < G->vernum; i++)
        {
            // 获取边始点和终点的下标
            v1 = LocateVex(G, head[i]);
            v2 = LocateVex(G, tail[i]);
            // 获取两个顶点所在的连通分量
            vs1 = Vexset[v1];
            vs2 = Vexset[v2];
            if(vs1 != vs2)
            {
                // 将新添加的边打印输出
                printf("(%d, %d)
    ", head[i], tail[i]);
                // 合并 vs1 和 vs2 两个分量,将两个集合统一
                for(j = 0; j < G->vernum; j++)
                    if(Vexset[j] == vs2)	// 集合编号为 vs2 的都改为 vs1
                        Vexset[j] = vs1;
            }
        }
    }
    

    代码来自严蔚敏《数据结构(C语言版)(第2版)》,实际上这个代码并没有交代清楚其背后的运行,还有阉割了两个数据结构的介绍。

    代码2

    void Kruskal(Graph G)
    {
        int EdgeAccepted;
        DisjSet S;	// 并查集(不相交集)
        PriorityQueue H;	// 优先队列
        Vertex U, V;
        SetType Uset, Vset;	// 并查集根的数据类型
        Edge E;
        
        // 初始化并查集,一开始每个顶点都在一个单独的集合中
        Intialize(S);
        // 构造优先队列(实际上就是对边的权值进行排序)
        ReadGraphIntoHeapArray(G, H);	// 将每条边放到优先队列中(此时未排序)
        BuildHeap(H);	// 对优先队列进行“排序”
        
        // 最小生成树中边的个数是顶点的个数减1
        EdgeAccepted = 0;
        while(EdgeAccepted < NumVertex - 1)
        {
            // 从优先队列取出权值为最小值的边并删除
            // E中有两个点,始点和终点,E = (U, V)
            E = DeleteMin(H);
            // 查找两个顶点所在的集合
            Uset = Find(U, S);
            Vset = Find(V, S);
            if(Uset != Vset)
            {
                // 输出生产的边
                printf("(%d, %d)
    ", U, V);
                EdgeAccepted++;
                // 合并两个集合
                SetUnion(S, Uset, Vset);
            }
        }
        
    }
    

    代码来自Mark Allen Weiss的《数据结构与算法分析 C语言描述》。

    不一定每天 code well 但要每天 live well
  • 相关阅读:
    IE block my cookie in iframe
    error app/styles/components/iconfont.scss (Line 12: Invalid GBK character "xE5")
    angular4开发过程中遇到的问题和知识点记录
    博客
    009android初级篇之APP中使用系统相机相册等集成应用
    012android初级篇之Handler机制
    android studio win7开发环境
    001windows已遇到一个关键性问题 一分钟后自动重启
    008android初级篇之jni中数组的传递
    006android初级篇之jni数据类型映射
  • 原文地址:https://www.cnblogs.com/geekfx/p/12423053.html
Copyright © 2020-2023  润新知