• 最小生成树--prim算法


         一个无向图G的最小生成树就是由该图的那些连接G的所有顶点的边构成的树,且其总价值最低,因此,最小生成树存在的充分必要条件为图G是连通的,简单点说如下:

    1.树的定义:有n个顶点和n-1条边,没有回路的称为树

    生成树的定义:生成树就是包含全部顶点,n-1(n为顶点数)条边都在图里就是生成树

    最小:指的是这些边加起来的权重之和最小

    2.判定条件:向生成树中任加一条边都一定构成回路

    充分必要条件:最小生成树存在那么图一定是连通的,反过来,图是连通的则最小生成树一定存在

      上图的红色的边加上顶点就是原图的一个最小生成树。

       给定一个图G,如何计算出该图的最小生成树,最通用的算法有两个,一是Prim算法,二是Kruskal算法,这里先讨论Prim算法。

       Prim算法和Dijkstra算法类似,我们对每一个顶点计算值dv和pv以及一个指标,该指标表示该顶点是已知的还是未知的,dv是连接v到已知顶点的最短边的权,pv是导致dv改变的最后的顶点,和Dijkstra算法不同的是dv的更新规则:在每一个顶点v被选取以后,对于每一个与v邻接的未知点w,dw=min{dw,cost(w,v)}.

      代码如下:

    #include<iostream>
    
    using namespace std;
    
    #define Inf 65535
    #define NotAVerter -1
    
    /////////////////////邻接表的相关定义//////////////////////
    typedef struct EdgeNode *position;
    typedef struct Led_table* Table;
     
     
     struct EdgeNode     //边表结点 
    { 
        int adjvex;    // 邻接点域,存储该顶点对应的下标 
        int weight;     // 对应边的权值
        position next; // 链域,指向下一个邻接点
    };
     
    struct Led_table       // 邻接表结构 
    { 
        int data;                //邻接表的大小
        position *firstedge;       //边表头指针,可以理解为数组
    }; 
     
     
    //////////////////////////邻接表相关函数定义///////////////
    Table Creat_Lable (int MaxElements)    //MaxElements参数为希望创建的节点数
    {
         
        Table table1 = static_cast<Table> (malloc(sizeof(struct Led_table)));
        table1->data = MaxElements;
        if (table1 == NULL)
        {
           cout << "out of space!!!";
        }
     
        table1->firstedge  = static_cast<position*>(malloc(sizeof(position)*(table1->data)));
        if (table1->firstedge  == NULL)
        {
           cout << "out of space!!!";
        }
     
        //给每个表头赋值,从0开始
        for (int i = 0; i <= table1->data - 1; ++i)
        {
            table1->firstedge [i] = static_cast<position>(malloc(sizeof(EdgeNode)));   //申请一个节点
            if (table1->firstedge [i]  == NULL)
                {
                   cout << "out of space!!!";
                }
            table1->firstedge [i]->adjvex = 0;   
            table1->firstedge [i]->weight = 0;   //此参数在此时没有意义
            table1->firstedge [i]->next = NULL;
     
        }
        return table1;
     
    }
     
     
    void Insert (Table table1, int v, int w, int weig)   //表示存在一条边为<v,w>,且权重为weig
    {
        position p = static_cast<position>(malloc(sizeof(EdgeNode)));   //申请一个节点
        if(p == NULL)
        {
           cout << "out of space!!!";
        }
        p->adjvex = w;
        p->weight = weig;
        p->next = table1->firstedge [v]->next;
        table1->firstedge [v]->next = p;
             
    }
    
    
    void Double_Insert (Table table1, int v, int w, int weig)   //无向边,双向插入
    {
    	Insert (table1, v,  w,  weig);
    	Insert (table1, w,  v,  weig);
    }
    
    /////////////////////最小生成树Prim算法/////////////////////////
    typedef struct Prim_tree *Prim_node ;
     
     struct Prim_tree     //
    { 
        bool know;
        int dist;    // 邻接点域,存储该顶点对应的下标 
        int path;     // 对应边的权值
    };
     
    Prim_node Prim_init(Table table1, int start)     //节点初始化
    {
        Prim_node Node  = static_cast<Prim_node>(malloc(sizeof(Prim_tree)*(table1->data)));
        if (Node  == NULL)
        {
           cout << "out of space!!!";
        }
        for(int i = 0; i != table1->data; ++i)
        {
            Node[i].know = false;
            Node[i].dist = Inf;
            Node[i].path = NotAVerter;
        }
        Node[start].dist = 0;   //起点处的距离设为0
        return Node;
    }
    
     void Prim_Algorithm (Table table1,Prim_node Node)  //prim 算法
     {
        int v;  
        for (int j = 0; j != table1->data; ++j)
        {
    		int zh = Inf;
            for (int i = 0; i != table1->data; ++i)    //找路径最小且没有标记过的点
            {
               if(!Node[i].know && zh > Node[i].dist )  //如果这个点是未知的,且距离比较小
               {
                  zh = Node[i].dist;
                  v = i;
               }
            
            }
    
            Node[v].know = true;    //标记这个点
            position p = table1->firstedge [v]->next;
            while (p != NULL)   //
            {
                if(!Node[p->adjvex].know && Node[p->adjvex].dist > p->weight  )
                {
                    Node[p->adjvex].dist =  p->weight;
                    Node[p->adjvex].path = v;
                }
                p = p->next;
            }
     
        }
         
     
     }
     
     
    
    int main ()
    {
    	 Table table_1 = Creat_Lable (7);    //创建一个大小为7的邻接表
     
      //根据图来为邻接表插入数据
       
      Double_Insert (table_1, 0, 1, 2);Double_Insert (table_1, 0, 2, 4);Double_Insert (table_1, 0, 3, 1);
      Double_Insert (table_1, 1, 3, 3);Double_Insert (table_1, 1, 4, 10);
      Double_Insert (table_1, 2, 5, 5);
      Double_Insert (table_1, 3, 2, 2);Double_Insert (table_1, 3, 5, 8);Double_Insert (table_1, 3, 6, 4);
      Double_Insert (table_1, 4, 3, 7);Double_Insert (table_1, 4, 6, 6);
      Double_Insert (table_1, 6, 5, 1);
       
      Prim_node Node_1 = Prim_init(table_1, 0);   //初始化节点
     
      Prim_Algorithm (table_1,Node_1);
    
      for (int i = 0; i != table_1->data; ++i)
      {
    	  cout << Node_1[i].dist << endl;
      }
    
    
    
    
    
       return 0;
    }
    

      与Dijkstra算法的代码类似,做点修改就好,该代码所用的例子就是上面的图,计算的结果也是那样的。

        夜深了,,,

       推荐一首歌《cry on my shoulder》

  • 相关阅读:
    爱上你的一百个理由 (网摘)
    梦想向右,沉默向左
    明夕何夕,君已陌路。
    不肯嫁的几种男人(转)
    一剪梅
    C# preprocessor Directives
    Language
    C# Language Tour
    Web application
    Unsafe code
  • 原文地址:https://www.cnblogs.com/1242118789lr/p/6880248.html
Copyright © 2020-2023  润新知