zoukankan      html  css  js  c++  java
  • Dijkstra和Prim算法的区别

    Dijkstra和Prim算法的区别

    1.先说说prim算法的思想:

    众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的点集合A,另一个集合为未加入生成树的点B,它的具体实现过程是:

    第1步:所有的点都在集合B中,A集合为空。

    第2步:任意以一个点为开始,把这个初始点加入集合A中,从集合B中减去这个点(代码实现很简单,也就是设置一个标示数组,为false表示这个点在B中,为true表示这个点在A中),寻找与它相邻的点中路径最短的点,如后把这个点也加入集合A中,从集合B中减去这个点(代码实现同上)。

    第3步:集合A中已经有了多个点,这时两个集合A和B,只要找到A集合中的点到B集合中的点的最短边,可以是A集合中的与B集合中的点的任意组合,把这条最短边有两个顶点,把在集合B中的顶点加入到集合A中,(代码实现的时候有点技巧,不需要枚举所有情况,也就是更新操作)。

    第4步:重复上述过程。一直到所有的点都在A集合中结束。

    2.说说dijkstra算法的过程:

    这个算法的过程有比prim算法的过程稍微多一点点步骤,但是思想确实巧妙的,也是贪心原理,它的目的是求某个源点到目的点的最短距离,总的来说,dijkstra算法也就是求某个源点到目的点的最短路,求解的过程也就是求源点到整个图的最短距离,次短距离,第三短距离等等(这些距离都是源点到某个点的最短距离)。。。。。求出来的每个距离都对应着一个点,也就是到这个点的最短距离,求的也就是原点到所有点的最短距离,并且存在了一个二维数组中,最后给出目的点就能直接通过查表获得最短距离。

    第1步:以源点(假设是s1)为开始点,求最短距离,如何求呢? 与这个源点相邻的点与源点的距离全部放在一个数组dist[]中,如果不可达,dist[]中为最大值,这里说一下,为什么要是一维数组,原因是默认的是从源点到这个一维数组下标的值,只需要目的点作为下标就可以,这时从源点到其他点的最短的“一”条路径有了,只要选出dist[]中最小的就行(得到最短路径的另一个端点假设是s2)。

    第2步:这时要寻找源点(假设是s1)到另外点的次短距离,这个距离或者是dist[]里面的值,或者是从第1步中选择的那个最短距离 + 从找到点(假设是s2)出发到其他点的距离(其实这里也是一个更新操作,更新的是dist[]里面的值),如果最短距离 + 从这点(假设是s2)到其他点的距离,小于dist[]里面的值,就可以更新dist[]数组了,然后再从dist[]数组中选一个值最小的,也就是第“二”短路径(次短路径)。

    第3步:寻找第“三”短路径,这时同上,第二短路径的端点(s3)更新与之相邻其他的点的dist[]数组里面的值。

    第4步:重复上述过程n - 1次(n指的是节点个数),得出结果,其实把源点到所有点的最短路径求出来了,都填在了dist[]表中,要找源点到哪个点的最短路,就只需要查表了。

     

     

     

    Dijkstra模版:

     

    //dijkstra算法模版,狄杰斯特拉算法模板,单源最短路模板
    //dijkstra算法模版
    
    #include <stdio.h>
    #include <string.h>
    #define MaxN 1001
    #define MaxInt 200000000
    int map[MaxN][MaxN],dist[MaxN];
    bool mark[MaxN];
    int n,start,end;
    int main()
    {
        int i,j,min1,minj,temp;
    
    //****************输入**********************
        scanf("%d%d%d",&n,&start,&end);
        for (i=1;i<=n;i++) 
            for (j=1;j<=n;j++)
                scanf("%d",&map[i][j]); 
    //******************************************
    //*****************初始化**********************
        for (i=1;i<=MaxN;i++)
            dist[i]=MaxInt;
        memset(mark,0,sizeof(mark));
        dist[start]=0;                  //把起点并入集合,搜索时就可以从起点寻找到第一条最短的边了
    //*********************************************
        for (i=1;i<=n-1;i++)
        {
            min1=MaxInt;
            for (j=1;j<=n;j++) //查找到原集合的最短的边
            {
                if (!mark[j]&&dist[j]<min1)
                {
                    min1=dist[j];
                    minj=j;
                }
            }
            mark[minj]=1;
            for (j=1;j<=n;j++) //每并入一个点都要对原来的边进行修正,保证任意时刻源点到目标点的距离都是最短的。
            {
                if (!mark[j]&&map[minj][j]>0)
                {
                    temp=dist[minj]+map[minj][j];
                    if (temp<dist[j]) 
                        dist[j]=temp;
                }
            }
        }
    //***********输出***************
        printf("%d
    ",dist[end]);
    //******************************
        return 0;
    }
    View Code

     

    Prim算法中寻找的是下一个与MST中任意顶点相距最近的顶点;  
    Dijkstra算法寻找的是下一个离给定顶点(单源)最近的顶点。
    另外,当有两条具有同样的最小权值的边可供选择时,任选一条即可,所以构造的MST不是惟一的。
    Prim算法和Dijkstra算法十分相似,惟一的区别是: Prim算法要寻找的是离已加入顶点距离最近的顶点;
    Dijkstra算法是寻找离固定顶点距离最近的顶点。
    所以Prim算法的时间复杂度分析与Dijkstra算法相同,都是 O(|V^2|)

    【拓】:Kruskal算法:http://baike.baidu.com/link?url=MchMLaw4a3nLu3bWSoEUEak-DYbM8n0H27ANKE5-Gv_frudxAvGfsqdpNRqDtdB0

    克鲁斯卡尔(Kruskal)算法(只与边相关)

    算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。

    算法过程:

    1.将图各边按照权值进行排序

    2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。

    不符合条件则继续遍历图,寻找下一个最小权值的边。

    3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。

    克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。

    代码:

    #include<iostream>
    #include<cstring>
    #include<string>
    
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MAX 1000
    int father[MAX], son[MAX];
    int v, l;
    
    typedef struct Kruskal //存储边的信息
    {
        int a;
        int b;
        int value;
    };
    
    bool cmp(const Kruskal & a, const Kruskal & b)
    {
        return a.value < b.value;
    }
    
    int unionsearch(int x) //查找根结点+路径压缩
    {
        return x == father[x] ? x : unionsearch(father[x]);
    }
    
    bool join(int x, int y) //合并
    {
        int root1, root2;
        root1 = unionsearch(x);
        root2 = unionsearch(y);
        if(root1 == root2) //为环
            return false;
        else if(son[root1] >= son[root2])
            {
                father[root2] = root1;
                son[root1] += son[root2];
            }
            else
            {
                father[root1] = root2;
                son[root2] += son[root1];
            }
        return true;
    }
    
    int main()
    {
        int ncase, ltotal, sum, flag;
        Kruskal edge[MAX];
        scanf("%d", &ncase);
        while(ncase--)
        {
            scanf("%d%d", &v, &l);
            ltotal = 0, sum = 0, flag = 0;
            for(int i = 1; i <= v; ++i) //初始化
            {
                father[i] = i;
                son[i] = 1;
            }
            for(int i = 1; i <= l ; ++i)
            {
                scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].value);
            }
            sort(edge + 1, edge + 1 + l, cmp); //按权值由小到大排序
            for(int i = 1; i <= l; ++i)
            {
                if(join(edge[i].a, edge[i].b))
                {
                    ltotal++; //边数加1
                    sum += edge[i].value; //记录权值之和
                    cout<<edge[i].a<<"->"<<edge[i].b<<endl;
                }
                if(ltotal == v - 1) //最小生成树条件:边数=顶点数-1
                {
                    flag = 1;
                    break;
                }
            }
            if(flag) printf("%d
    ", sum);
            else printf("data error.
    ");
        }
        return 0;
    }
    View Code

     

     

     

  • 相关阅读:
    常见linux内核线程说明
    /proc/modules分析
    linux用户空间和内核空间(内核高端内存)_转
    二层交换机/三层交换机/路由器
    NAT--Network Address Translator
    curl命令使用
    (转)XML中必须进行转义的字符
    LFCP
    IPSP问题
    API和schema开发过程问题汇总
  • 原文地址:https://www.cnblogs.com/yuyixingkong/p/3464267.html
Copyright © 2011-2022 走看看