码迷,mamicode.com
首页 > 其他好文 > 详细

区别 最短路跟最小生成树

时间:2015-05-25 11:29:02      阅读:274      评论:0      收藏:0      [点我收藏+]

标签:graph   算法   mst   最短路   

首先是定义上


最小生成树能够保证整个拓扑图的所有路径之和最小,但不能保证任意两点之间是最短路径。
最短路径是从一点出发,到达目的地的路径最小。


实现方法
1. 最小生成树
最小生成树有两种算法来得到:Prims算法和Kruskal算法
Kruskal算法:根据边的加权值以递增的方式,一次找出加权值最低的边来构建最小生成树,而且规定:每次添加的边不能造成生成树有回路,知道找到N-1个边为止。
Prims算法:以每次加入一个的临界边来建立最小生成树,直到找到N-1个边为止。其规则为:以开始时生成树的集合(集合U)为起始的定点,然后找出与生成树集合邻接的边(集合V)中,加权值最小的边来建立生成树,为了确定新加入的边不会造成回路,所以每一个新加入的边,只允许有一个顶点在生成树集合中,重复执行此步骤,直到找到N-1个边为止。

以prime算法为例。注意松弛操作部分

#include<iostream>//最小生成树
#define INF 0x1f1f1f1f
#define M 1000
using namespace std;
double dis[M],map[M][M];
bool flag[M];
int prim(int s,int n)                        //s为起点,n为点的个数
{
    int i,j,k,temp,md,total=0;
    for(i=1;i<=n;i++)
        dis[i]=map[s][i];                    //与最短路不同,而是将dis置为map[s][i]
    memset(flag,false,sizeof(flag));
    flag[s]=true;                            //将起点加入集合
    for(i=1;i<n;i++){                        //依旧进行n-1次迭代,每次找到不在集合的最小边(n个点有n-1条边)!!!!!!
        md=INF;
    for(j=1;j<=n;j++){
        if(!flag[j]&&dis[j]<md){
            md=dis[j];
            temp=j;
        }
    }
    flag[temp]=true;                      //将找到的最小边的点加入集合
    total+=md;                            //并将这个边的权值加到total中
    for(j=1;j<=n;j++)                     //松弛操作,注意与最短路不同
    if(!flag[j]&&dis[j]>map[temp][j])
        dis[j]=map[temp][j];
       }
    return total;
}



2 最短路径


算法描述
(这里描述的是从节点1开始到各点的dijkstra算法,其中Wa->b表示a->b的边的权值,d(i)即为最短路径值)  
1. 置集合S={2,3,...n}, 数组d(1)=0, d(i)=W1->i(1,i之间存在边) or +无穷大(1.i之间不存在边)  
2. 在S中,令d(j)=min{d(i),i属于S},令S=S-{j},若S为空集则算法结束,否则转3  
3. 对全部i属于S,如果存在边j->i,那么置d(i)=min{d(i), d(j)+Wj->i},转2  


Dijkstra算法思想为:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将 加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。 
算法具体步骤   
(1)初始时,S只包含源点,即S=,v的距离为0。U包含除v外的其他顶点,U中顶点u距离为边上的权(若v与u有边)或 ∞(若u不是v的出边邻接点)。  
(2)从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。  
(3)以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u(u U)的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值为顶点k的距离加上边上的权。  
(4)重复步骤(2)和(3)直到所有顶点都包含在S中。
复杂度分析
Dijkstra 算法的时间复杂度为O(n^2)  空间复杂度取决于存储方式,邻接矩阵为O(n^2)

下面写一下dijkstra为例,主要是松弛操作部分跟prime算法的区别

#include<stdio.h>  //最短路  
#define maxsum 0x3fffffff    
int map[101][101],dist[101],s[101];    
void Dijkstra(int n,int x)  //n,1,递推实现  
{    
    int mindis,u,i,j;    
    for(i=1;i<=n;i++)    
    {    
        dist[i]=map[i][x];//map[x][i] is OK,dist表示i到原点的最小距离!  
        s[i]=0; //printf("%d/n",dist[i]);  
    }    
    s[x]=1;// x=1  
    for(i=1;i<=n;i++)    
    {    
        mindis=maxsum;    
        u=-1;   
        // 找出当前未使用的点j的dist[j]最小值  
        for(j=1;j<=n;j++)  
        if(s[j]==0 && dist[j]<mindis)//------------(2)  
        {    
            u=j;  //保存当前邻接点中最小的  
            mindis=dist[j];    
        }    
        s[u]=1;//u点已存入s集合,最小的!所以放外面   
        //更新dist  
        for(j=1;j<=n;j++)  //-------------------(3)  
          if(s[j]==0)    
            if( dist[u]+map[u][j]<dist[j] && map[u][j]<maxsum) //从u点发散出去寻找,map[u][j]<maxsum存在权值 ,map[j][u] is OK   
            dist[j]=dist[u]+map[u][j];    
    }    
}    
int main()    
{    
    int n,m,a,b,c,i,j;    
    while(scanf("%d%d",&n,&m)!=EOF)    
    {    
        if(n==0&&m==0) break;    
        for(i=1;i<=n;i++)    
          for(j=1;j<=n;j++)    
          map[i][j]=maxsum;//初始化邻接矩阵  
        for(i=1;i<=m;i++)    
        {   
            scanf("%d%d%d",&a,&b,&c);    
            map[a][b]=map[b][a]=c;//构造邻接矩阵,对称的!无向!  
        }    
        Dijkstra(n,1);    
        printf("%d/n",dist[n]);  
    }    
    return 0;    
}     




区别 最短路跟最小生成树

标签:graph   算法   mst   最短路   

原文地址:http://blog.csdn.net/sheldon761642718/article/details/45967559

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!