关于最近做一些最小生成树(MST)题的想法

想法:

最小生成树问题至此告一段落,回想一下关于这方面的题目做了不少天了,虽然做的题目不算多吧,求最小生成树的问题有两个经典的算法:Prim算法和Kruskal算法,个人认为Prim算法适合在给边之间的权值是通过数组给出的,Kruskal算法适合于通过给边的信息给出权值信息,不过给出边的信息转化成数组信息用Prim算法还是很容易的。

这两种算法各有所长,现将优缺点列表如下:

Prim算法:适合于通过数组给出权值信息的无向图,可以处理一些已给出MST边的信息的无向图,在对数组赋值的时候运用一些技巧(赋值为0或者负值)。时间复杂度:O(nlogn),适合于求稠密图。

补充:Prim算法也可以求一些边的信息,只不过要用一个数组(int father[])来标记对于点i距离最近的点的标号father[i]。应用:POJ 1753 Highways解题报告

Kruskal算法:适合于通过给出边的信息的无向图,可以求最大生成树问题,时间复杂度:O(eloge),适合于就稀疏图。


代码实现:

Prim算法:
/*==================================================*\ 
| Prim 求MST 
| INIT: cost[][]耗费矩阵(inf为无穷大,表示两个顶点之间不连通,(u,v)不属于E); 
| CALL: prim(cost, n); 返回-1代表原图不连通; 
\*==================================================*/  
#define typec int // type of cost  
const typec inf = 0x3f3f3f3f; // max of cost  
int vis[V]; typec lowc[V];  
typec prim(typec cost[][V], int n){ // vertex: 0 ~ n-1  
    int i, j, p;  
    typec minc, res = 0;  
    memset(vis, 0, sizeof(vis));  
    vis[0] = 1;  
    for (i=1; i<n; i++) lowc[i] = cost[0][i];  
    for (i=1; i<n; i++) {  
    minc = inf; p = -1;  
    for (j=0; j<n; j++)  
        if (0 == vis[j] && minc > lowc[j]) {  
        minc = lowc[j]; p = j;  
    }  
    if (inf == minc) return -1; // 原图不连通  
    res += minc; vis[p] = 1;  
    for (j=0; j<n; j++)  
        if (0 == vis[j] && lowc[j] > cost[p][j])  
            lowc[j] = cost[p][j];  
    }  
    return res;   //返回最小权值和  
}  

Kruskal算法:
struct edge{  
    int u, v, w;  
};  
  
const int NODE_NUM = 102;  
edge e[NODE_NUM*NODE_NUM];  
int father[NODE_NUM];  
int n, ne;    //n是顶点的个数,ne是边的个数  
  
bool cmp(const edge& a, const edge& b)  
{  
    return a.w < b.w;   //return a.w > b.w; ---是求最大生成树  
}  
  
void make_set()  
{  
    for (int i = 1; i <= n; ++i)  
        father[i] = i;  
}  
  
int find_set(int i)  
{  
    if (father[i] != i){  
        father[i] = find_set(father[i]);  
    }  
    return father[i];  
}  
  
bool union_set(int a, int b) //a --> b  
{  
    a = find_set(a);  
    b = find_set(b);  
    if (a != b){  //没有共同祖先,说明没有形成回路  
        father[a] = b; //将节点纳入最小生成树集合  
        return true;  
    }  
    else{  
        return false;  
    }  
}  
  
int kruskal()  
{  
    int i, mst_edge = 0, sum = 0;  
    make_set();  
    sort(e, e+ne, cmp);  //将边按升序排序  
    for (i = 0; i < ne; ++i){  
        //如果加入的边不会使树形成回路  
        if (union_set(e[i].u, e[i].v)){  
            sum += e[i].w;  
            //如果纳入的边数等于顶点数-1,则说明最小生成树形成  
            if (++mst_edge == n - 1){  
                return sum;    //如果图是连通图,返回权值  
            }  
        }  
    }  
    return mst_edge;   //如果不是连通图,则返回最大的连通(可以是多个生成树)的边的个数,  
}  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值