最小生成树

一个有n个节点的连通图的生成树是原图的极小连通子图,且包含原图中的所有n个结点,并且有保持图连通的最少的边。最小生成树可以用Kruskal算法或者prim算法求出。

kruskal 算法的过程为不断对子图进行合并,直到形成最终的最小生成树。prim 算法的过程则是只存在一个子图,不断选择顶点加入到该子图中,即通过对子图进行扩张,直到形成最终的最小生成树。

https://www.jianshu.com/p/cf21443b3838

此网址对着两种算法做了详细介绍

prim算法

最小生成树的一个典型问题

poj-1258

题意:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。

输入:输入包含多组数据。对于每组数据, 第一行包含一个整数N表示农场的数量 (3 <= N <= 100). 接下来是一个N*N的邻接矩阵,表示各个村庄之间的距离 . 当然,对角线将是0,因为从农场到农场的距离对于这个问题并不有趣。

输出:对于每种情况,请输出一个整数表示长度,该长度是连接整个农场集合所需的最小光纤长度的总和。

#include<iostream>
#include<cstring>
using namespace std;
int init[105][105],N;//无向图的邻接矩阵
int vis[105]={0},mincost[105];//vis标记已经走过的节点,mincoat表示从x定点出发的边到每个顶点的最小权值
/************************最小生成树的prim算法************************/
int prim()//从某个顶点出发,不断添加边
{
    int minsum=0;//最小边之和
    vis[0]=1;//从第一个顶点开始,标记
    for(int i=0;i<N;i++)
        mincost[i]=init[0][i];//标记从第一个顶点出发的边的最小权值
    for(int i=1;i<N;i++){
        int MIN=100005,node;//MIN的一般写法是MIN=inf
        for(int j=1;j<N;j++){
            if(!vis[j]&&mincost[j]<MIN){//比较权值,寻找下一个顶点
                MIN=mincost[j];
                node=j;//标记权值最小的顶点
            }
        }
        //用来处理无法连通的问题
        //if(MIN==inf){
        //    cout<<"NO"<<endl;
        //    return;
        //}
        vis[node]=1;//标记权值最小的顶点
        minsum+=MIN;//题目答案,最小和相加
        for(int j=1;j<N;j++){
            if(!vis[j]&&mincost[j]>init[node][j])
                mincost[j]=init[node][j];//找出当前顶点下与上一顶点下的最小权值
        }
    }
    return minsum;//求得题目最终的最小和
}
int main()
{
    while(cin>>N)
    {
        memset(init,0,sizeof(init));
        memset(vis,0,sizeof(vis));
        memset(mincost,0,sizeof(mincost));
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++)
            cin>>init[i][j];
        cout<<prim()<<endl;
    }
    return 0;
}