zoukankan      html  css  js  c++  java
  • Prim算法解决最小生成树

    一、最小生成树问题

    什么是最小生成树问题?给你一个带权连通图,需要你删去一些边,使它成为一颗权值最小的树。

    二、Prim算法

    1)输入:输入一个带权连通图,顶点集合V,边集合E

    2)初始化:Vnew={x},x为任意一个顶点,作为起始点,Enew={},为空

    3)在集合E中选择权值最小的边<u,v>,其中u为集合Vnew中的顶点,而v不在集合Vnew中但在V中,(若有多条满足条件且权值相同时,可任选其中一条)

    4)将v收录集合Vnew中,将<u,v>收录Enew中

    5)重复步骤4、5,直到所有的顶点都被收录到Vnew中

    6)输出:输出由Vnew和Enew所描述的最小生成树

    证明:

    这就是一个朴素的贪心,我们只需证明这种贪心策略是正确的。先看一下这个性质:

     MST性质:设G=(V,E)是一个连通网络,U是顶点集V的一个真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。

    假如通过其他途径,已经得到一颗不包含(u,v)的最小生成树,那么把(u,v)加入到这棵生成树,必定成环,由于在某点没有选(u,v),则必定可以在环上找到一个权值不小于(u,v)的边,删去此边,用(u,v)代替,仍是一颗最小生成树且总权值更小。所以由反证法知,一定存在一棵最小生成树包含(u,v)。所以可以通过每次选择符合条件的权值最小边,来得到其中一种最小生成树。

    三、算法实现

    思路:这里用邻接矩阵A存储图(因为Prim适合稠密图,时间复杂度一般为O(n^2)),用数组lowcost[MAXN]记录未收录顶点到Vnew的最小费用,用vis[MAXN]记录是否已收录。

    1)任取一顶点s,收录到Vnew中(这里简化为vis[s] = true)

    2) 初始化,将lowcost[x]初始化为到s的费用

    将下列步骤进行n-1次

    3)找到最小的lowcost[x]

    4)若没有找到符合条件的最小lowcost[x],跳出循环

    5)将x收录到Vnew

    6)  更新lowcost[ ]  (因为新收录的顶点可能影响lowcost)

    7)若有顶点未被收录,说明图不连通

    代码:

    #include<cstdio>
    #include<stdbool.h>
    #include<vector>
    const int INF = 0x3f3f3f3f;
    const int MAXN = 100 + 10;
    bool vis[MAXN];
    int lowcost[MAXN];
    int cost[MAXN][MAXN];
    //点是从0 ~ n-1
    //耗费矩阵cost[][] 
    int Prim(int cost[][MAXN], int s, int n)
    {
        int ans = 0;
        memset(vis, false, sizeof(vis));
        vis[s] = true;
        for (int i = 0; i < n; i++)  lowcost[i] = cost[s][i];
        for (int i = 1; i < n; i++)
        {
            int minc = INF;
            int pos = -1;
            for (int j = 0; j < n; j++)
            {
                if (!vis[j] && lowcost[j] < minc)
                {
                    minc = lowcost[j];
                    pos = j;
                }
            }
            if (i < n - 1 && pos < 0)  return -1;
            vis[pos] = true;
            ans += minc;
            for (int j = 0; j < n; j++)
            {
                if (!vis[j] && cost[pos][j] < lowcost[j])
                    lowcost[j] = cost[pos][j];
            }
        }
        return ans;
    }
    View Code

    四、算法优化

    据说可以用二叉堆、斐波那契堆等,先给自己挖一个坑,日后再补吧。

  • 相关阅读:
    Android应用程序注冊广播接收器(registerReceiver)的过程分析
    智能生活 “视”不可挡——首届TCL杯HTML5智能电视开发大赛等你来挑战
    点滴的积累---J2SE学习小结
    公开课
    iOS学习之 plist文件的读写
    【STL】关联容器 — hash_set
    《Pro Android Graphics》读书笔记之第三节
    第一章. ActionScript 语言基础
    JAVA数组的定义及用法
    MS-SQLSERVER中的MSDTC不可用解决方法
  • 原文地址:https://www.cnblogs.com/lfri/p/9307871.html
Copyright © 2011-2022 走看看