zoukankan      html  css  js  c++  java
  • 最小生成树(prim)

    里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。

    介绍如下:

    http://baike.baidu.com/link?url=nDhHyOlu8i90Hm5bjUycarVdBPN8BXQvnv8NGwl0g4MLlLkmkFLwf7xs1-JBWCRkQw5qDU6cIwh1ov7fyRRxQK

    原理可以参考这几篇文章:

    http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html

    http://blog.csdn.net/weinierbian/article/details/8059129

    http://blog.chinaunix.net/uid-25324849-id-2182922.html

    prim算法适合稠密图,邻接矩阵时间复杂度为O(n^2),邻接表为O(eloge),其时间复杂度与边得数目无关。

    而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。

    邻接矩阵实现:

      1 #include <iostream>
      2 using namespace std;
      3 
      4 #define MAXVEX 20
      5 #define MAXEDGE 20
      6 #define INFINITY 65535
      7 
      8 
      9 
     10 typedef struct
     11 {
     12           int vexs[MAXVEX];
     13           int arc[MAXVEX][MAXVEX];
     14           int numVertexes,numEdges;
     15 }MGraph;
     16 
     17 typedef int Patharc[MAXVEX];
     18 typedef int ShortPathTable[MAXVEX];
     19 
     20 bool visited[MAXVEX];//保存已访问的数组
     21 int father[MAXVEX];
     22 int closeset[MAXVEX];
     23 
     24 void CreateGraph(MGraph* G)
     25 {
     26           cout<<"请输入边数和顶点数:
    ";
     27           int d,n,i,j;
     28           cin>>d>>n;
     29           G->numVertexes = n;
     30           G->numEdges = d;
     31 
     32           //给顶点和边初始化
     33           for(i = 0;i<G->numVertexes;i++)
     34                     G->vexs[i] = i;
     35           for(i = 0;i<G->numVertexes;i++)
     36           {
     37                     for(j = 0;j<G->numVertexes;j++)
     38                     {
     39                               if(i==j)
     40                                         G->arc[i][j] = 0;
     41                               else
     42                                         G->arc[i][j] = G->arc[j][i] = INFINITY;
     43                     }
     44           }
     45 
     46           G->arc[0][1]=1;
     47           G->arc[0][2]=5;
     48           G->arc[1][2]=3;
     49           G->arc[1][3]=7;
     50           G->arc[1][4]=5;
     51 
     52           G->arc[2][4]=1;
     53           G->arc[2][5]=7;
     54           G->arc[3][4]=2;
     55           G->arc[3][6]=3;
     56           G->arc[4][5]=3;
     57 
     58           G->arc[4][6]=6;
     59           G->arc[4][7]=9;
     60           G->arc[5][7]=5;
     61           G->arc[6][7]=2;
     62           G->arc[6][8]=7;
     63 
     64           G->arc[7][8]=4;
     65 
     66           for(i = 0;i<G->numVertexes;i++)
     67           {
     68                     for(j = i;j<G->numVertexes;j++)
     69                     {
     70                               G->arc[j][i] = G->arc[i][j];
     71                     }
     72           }
     73 }
     74 
     75 
     76 int prim(MGraph G, Patharc *P, ShortPathTable *D)
     77 {
     78           int v,w;
     79 
     80           //init
     81           for(v = 0;v<G.numVertexes;v++)
     82           {
     83                     visited[v] = false;
     84                     (*D)[v] = G.arc[0][v];
     85                     father[v] = -1;
     86                     closeset[v] = 0;
     87           }
     88           visited[0] = true;
     89 
     90           int len = 0;
     91           int nlen,nid;
     92 
     93           //求得下一个符合条件的点
     94           for(v = 1;v<G.numVertexes;v++)
     95           {
     96                    nlen = INFINITY;
     97                    for(w = 0;w<G.numVertexes;w++)
     98                    {
     99                              if(!visited[w] && (*D)[w]<nlen)
    100                              {
    101                                        nlen = (*D)[w];
    102                                        nid = w;
    103                              }
    104                    }
    105 
    106                    len += nlen;
    107                    visited[nid] = true;
    108                    father[nid] = closeset[nid];
    109 
    110                    for(w = 0;w<G.numVertexes;w++)
    111                    {
    112                              if(!visited[w] && (*D)[w]>G.arc[nid][w])
    113                              {
    114                                        (*D)[w] = G.arc[nid][w];
    115                                        closeset[w] = nid;
    116                              }
    117                    }
    118 
    119 
    120           }
    121 
    122           return len;
    123 
    124 }
    125 
    126 
    127 int main()
    128 {
    129           int v0,i,j;
    130 
    131           MGraph G;
    132 
    133           Patharc P;
    134           ShortPathTable D;
    135 
    136           CreateGraph(&G);
    137 
    138           int d = prim(G,&P,&D);
    139 
    140           cout<<"最小树如下:
    ";
    141           for(i = 1;i<G.numVertexes;i++)
    142           {
    143                    cout<<"("<<i<<","<<father[i]<<") ";
    144           }
    145           cout<<endl;
    146 
    147           cout<<"最短路径长度为:
    ";
    148 
    149           cout<<d<<endl;
    150 
    151           return 0;
    152 
    153 
    154 }

    我是用vector和pair的邻接表实现的,然后用两个list保存两个集合,一个最小生成树集,一个其他集

    实现如下:

      1 #include <iostream>
      2 #include <vector>
      3 #include <queue>
      4 #include <list>
      5 using namespace std;
      6 
      7 vector<pair<int,int> > eg[100];
      8 
      9 vector<pair<int,int> > result;
     10 
     11 typedef pair<int,int> pa;
     12 
     13 bool visit[100];
     14 
     15 list<int> setOfPrim;
     16 
     17 list<int> outOfPrim;
     18 
     19 int lowcost[100] = {0};
     20 
     21 void prim(int n,int d)
     22 {
     23           int min,aim,sta;
     24           bool is;
     25 
     26           list<int>::iterator sop;//最小树集合
     27           list<int>::iterator oop;//其他集合
     28           vector<pair<int,int> >::iterator it;
     29 
     30           setOfPrim.push_back(0);//放入起始点0进最小树集合
     31 
     32           //初始化其他集合
     33           for(int i = 1;i<n;i++)
     34                    outOfPrim.push_back(i);
     35 
     36           while(!outOfPrim.empty())//其他集合不为空
     37           {
     38                     //遍历最小树集合,sop,寻找与集合最近的点
     39                     min = 1<<16;
     40                     for(sop = setOfPrim.begin();sop!=setOfPrim.end();sop++)
     41                     {
     42                               //遍历sop邻接点
     43                               for(int i = 0;i<eg[*sop].size();i++)
     44                               {
     45                                         pa x = eg[*sop][i];
     46                                         is = false;
     47 
     48                                         //如果点属于oop集合
     49                                         for(oop = outOfPrim.begin();oop!=outOfPrim.end();oop++)
     50                                         {
     51                                                   if(*oop == x.first)
     52                                                   {
     53                                                             is = true;
     54                                                   }
     55                                         }
     56 
     57                                         if(is)
     58                                         {
     59                                                   if(x.second<min)
     60                                                   {
     61                                                             min = x.second;
     62                                                             aim = x.first;
     63                                                             sta = *sop;
     64                                                   }
     65                                                   //min存放了离sop集合最近的点的距离
     66                                                   //aim存放了点的序号
     67                                         }
     68                               }
     69                     }
     70 
     71                     setOfPrim.push_back(aim);
     72                     result.push_back(make_pair(sta,aim));
     73                     for(oop = outOfPrim.begin(); oop != outOfPrim.end(); )
     74                     {
     75                               if(*oop == aim)
     76                               {
     77                                         oop = outOfPrim.erase(oop);
     78                                         if(outOfPrim.empty())
     79                                                   break;
     80                               }
     81                               else
     82                                         oop++;
     83                     }
     84                     cout<<"The set of prim:
    ";
     85                     for(sop = setOfPrim.begin(); sop != setOfPrim.end();sop++)
     86                     {
     87                               cout<<*sop<<" ";
     88                     }
     89                     cout<<"
    The set of not prim:
    ";
     90                     for(oop = outOfPrim.begin(); oop != outOfPrim.end();oop++)
     91                     {
     92                               cout<<*oop<<" ";
     93                     }
     94                     cout<<endl;
     95 
     96                     for(it = result.begin();it!=result.end();it++)
     97                     {
     98 
     99                               cout<<"("<<(*it).first<<","<<(*it).second<<")";
    100                     }
    101                     cout<<endl<<endl;
    102           }
    103 }
    104 
    105 
    106 int main()
    107 {
    108           int n,d;
    109           cin>>n>>d;
    110           for(int i = 0;i<d;i++)
    111           {
    112                     int t,s,w;
    113                     cin>>t>>s>>w;
    114                     eg[t].push_back(make_pair(s,w));
    115                     eg[s].push_back(make_pair(t,w));
    116           }
    117           prim(n,d);
    118 
    119 
    120 
    121 }
    122 /*
    123 6 8
    124 0 1 2
    125 0 3 4
    126 1 4 4
    127 2 0 5
    128 2 5 2
    129 3 4 3
    130 3 5 7
    131 5 4 3
    132 */

    另外,因为prim算法和Dijkstra算法很像,这篇文章有讲两者之间的区别:

    http://www.cnblogs.com/CheeseZH/archive/2012/10/09/2717106.html

  • 相关阅读:
    图片切换的练习
    固定定位
    绝对定位
    相对定位
    全局作用域 变量声明
    3种循环语句 JS基础
    解除绑定事件 和 封装兼容性addEvent 来处理针对于不同浏览器的兼容方法
    插入排序法 猴子选大王 检索的数组 验证身份证号码 练习
    [z]JSONP例子
    ireport related
  • 原文地址:https://www.cnblogs.com/qlky/p/4987190.html
Copyright © 2011-2022 走看看