グラフアルゴリズム - 最小スパニングツリー

グラフアルゴリズム - 最小スパニングツリー

無向グラフをチェックしてみてください最小スパニングツリー(最小スパニングツリー)、有向グラフのこの問題は、意味のある、それらを見つけることがより困難です。場合にのみ、図場合は最小全域木があります。 G G 接続されています。最小スパニングツリーの中のエッジの数 V 1 \左| V \権| -1

プリム法

各ステップで、我々はルートとしてノードを入れて、サイドを追加する必要があります。いずれかの時点で、我々はまだアルゴリズムの各段階で、この場合、ツリーに追加されていない残りの頂点は、エッジによって選択することができるが、頂点のセットは、ツリーに追加されたアルゴリズムを見ることができます ( u , v ) (U、V) 、そのように ( u , v ) (U、V) の全ての値 u 木ではなく v V 最小境界値は、ツリーに存在せず、新しい頂点を発見し、このツリーに追加します。

コード

本明細書に隣接行列を使用します。

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)\n", 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)
请按任意键继续. . .

クラスカル法

第二の戦略は、右の最小端側に応じて選択連続貪欲であり、それは与えられたエッジを置くのにかかるように選択されたエッジリングが発生しない場合。

コード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)\n", 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つのデータ構造があります。

コード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)\n", U, V);
            EdgeAccepted++;
            // 合并两个集合
            SetUnion(S, Uset, Vset);
        }
    }
    
}

マーク・アレンワイス・コード「C言語のデータ構造とアルゴリズム解析。」

发布了32 篇原创文章 · 获赞 18 · 访问量 3229

おすすめ

転載: blog.csdn.net/u011714517/article/details/104302639
おすすめ