1399 最小生成树(Prim算法1)

1399 最小生成树

  • 描述: 最小生成树问题是实际生产生活中十分重要的一类问题。假设需要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,自然需要考虑这样一个问题,即如何在最节省经费的前提下建立这个通信网。
    可以用连通网来表示n个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。现在,需要选择一棵生成树,使总的耗费最小。这个问题就是构造连通网的最小代价生成树,简称最小生成树。一棵生成树的代价就是树上各边的代价之和。
    而在常用的最小生成树构造算法中,普里姆(Prim)算法是一种非常常用的算法。
    在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法建立最小生成树,并输出最小生成树的代价。

  • 输入:输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
    以后的n行中每行有n个用空格隔开的整数,对于第i行的第j个整数,如果不为0,则表示第i个顶点和第j个顶点有直接连接且代价为相应的值,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
    输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图,且保证图中只有一个连通分量。

  • 输出:只有一个整数,即最小生成树的总代价。请注意行尾输出换行。

  • 输入示例

    4
    0 2 4 0
    2 0 3 5
    4 3 0 1
    0 5 1 0
    
  • 输出示例

    6
    
  • 代码块

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 9999
    #define NotAVertex (-1)
    
    const int N = 51;
    
    int VexNum;//顶点的数目
    
    //《数据结构与算法分析》中关于prim的代码(其实都一样)
    typedef int Vertex;//顶点的类型
    typedef struct TableEntry{
        int adj[N];//此顶点连接到的点的权值
        int Known;//此顶点是否为已知
        int Dist;//Dv表示连接v到已知顶点最短边的权
        Vertex Path;//Pv表示导致Dv改变的最后的顶点
    }Table[N];//每个顶点都带有此三种信息
    
    //  table表初始状态:              ==>          v0加入生成树 
    //  v    Known    Dv    Pv                      v    Known    Dv    Pv 
    //  v0     0     inf    -1                      v0     1      0     0
    //  v1     0     inf    -1        ==>           v1     0      4     0
    //  v2     0     inf    -1                      v2     0      2     0
    //  v3     0     inf    -1                      v3     0     inf    0
    
    void InitTable(Table &T){
        int n; scanf("%d", &n); 
        VexNum = n;
    
        for(int i=0; i<n; ++i){
            for(int j=0; j<n; ++j){
                scanf("%d", &T[i].adj[j]);
                if(i!=j && T[i].adj[j]==0){
                    T[i].adj[j] = inf;
                }
            }     
        }  
    
        for(int i=0; i<n; ++i){
            T[i].Known = 0;
            T[i].Dist = inf;
            T[i].Path = NotAVertex;
        }
    }
    
    int Prim(Table &T){
        //初始化表
        InitTable(T);
    
        int cost = 0;
    
        //将第一个点加入生成树(随便一个点,这里用第0个点)
        T[0].Known = 1;
        for(Vertex i=0; i<VexNum; ++i){
            T[i].Dist = T[i].adj[0];//其他点到0的距离
            T[i].Path = 0;//引起Di该边的点都是0
        }
    
        for(int i=1; i<VexNum; ++i){//共循环VexNum-1次才能保证每个顶点都遍历一遍
            int min = inf; Vertex V;//V是选中的点(smallest unknow distance vertex)
            for(Vertex j=0; j<VexNum; ++j){
                if(T[j].Known==0 && T[j].Dist<min){
                    V = j;
                    min = T[j].Dist;
                }
            }
            T[V].Known = 1;//标记V已经加入生成树
            cost = cost + min;
            //更新未标记的集合(know == 0)到已标记的集合(Know == 1)的最短距离,其实就是刚加入点的影响
            Vertex W;
            for(W=0; W<VexNum; ++W){
                if(T[W].Known==0 && T[W].adj[V]<T[W].Dist){//未标记的顶点到V的距离比未标记的顶点到已知顶点(除V以外)小
                    T[W].Dist = T[W].adj[V];
                    T[W].Path = V;//V是引起Dw变化的点
                }
            }
        }
        return cost;
    }
    
    int main(){
        Table T;
        printf("%d\n", Prim(T));
        system("pause");
        return 0;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值