zoukankan      html  css  js  c++  java
  • 最短路径---Dijkstra/Floyd算法

    1.Dijkstra算法基础:

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

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

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

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

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

    在未选点集中选择一个最短距离最小的未选点k来扩充已选集是Dijkstra算法的关键。时间复杂度O(n^2).

     1 void Init_Dijkstra(void)
     2 {
     3     count=0;
     4     for(int i=0;i<MG->n;i++)
     5     {
     6         vis[i]=0;  //状态置0,表示没有求出最短路径
     7         min_wg[i]=MG->edge[START][i];
     8         
     9         if(min_wg[i] == INF)
    10             min_from[i]=-1;  //表示到顶点i路径最短的上一个顶点不存在
    11         else
    12             min_from[i]=START;
    13     }
    14 
    15     vis[START]=1;
    16     count++;
    17     min_wg[START]=0;  //从源点到达源点的边权值为0
    18     min_from[START]=START;  //源点的父节点为本身
    19 }
    20 
    21 void Dijkstra(void)
    22 {
    23     int min,to_index;
    24     int new_dis;  //距离更新中间值
    25     
    26     while(count < MG->n)
    27     {
    28         min=INF;
    29         to_index=-1;
    30         for(int i=0;i<MG->n;i++)
    31             if(!vis[i] && (min_wg[i] < min))
    32             {
    33                 min=min_wg[i];
    34                 to_index=i;
    35             }
    36 
    37         if(to_index != -1)
    38         {    
    39 //            if(to_index == ENDN)  //用于[2]
    40 //                break;
    41             vis[to_index]=1;
    42             count++;
    43         }
    44         else
    45             break;
    46 
    47         for(int j=0;j<MG->n;j++)
    48             if(!vis[j] && MG->edge[to_index][j] < INF)
    49             {
    50                 new_dis=min_wg[to_index]+MG->edge[to_index][j];
    51                 if(new_dis < min_wg[j])
    52                 {
    53                     min_wg[j]=new_dis;
    54                     min_from[j]=to_index;
    55                 }
    56             }
    57     }
    58 }
     1 //查找from->to的路径
     2 void SearchPath(int from,int to)
     3 {
     4     int tot=0;
     5     int index_temp;  //缓存索引
     6 
     7     path[tot++]=to;
     8     index_temp=min_from[to];
     9     while(index_temp != from)  //回溯找到源点 
    10     {
    11         path[tot++]=index_temp;
    12         index_temp=min_from[index_temp];
    13     }
    14     path[tot]=from;
    15 
    16     printf("%c",MG->vertex[from]);
    17     for(int i=tot-1;i>=0;i--)  //对辅助数组进行逆向输出 
    18         printf("->%c",MG->vertex[path[i]]);
    19     printf("
    ");
    20 }

     2.Floyd算法

            Floyd算法用于求最短路径,经典的动态规划或是有多个起点和多个终点,是解决任意两点间最短路径的一种算法,可正确处理有向图或边负的最短路径问题,但不许有包含带负权的边组成的回路。Floyd算法可以说Warshall算法的扩展,三个for循环解决问题,时间复杂度为O(n^3)。Floyd算法的基本思想:从任意节点A到任意点B的最短路径不外乎2种可能:1是直接从A到B,2是从A经过若干个节点X到B。所以我们设Dis(AB)为节点A到B最短路径距离,对于每一个点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如成立,证明从A到X再到B的路径比A直接到B的路径短,便Dis(AB) = Dis(AX) + Dis(XB),这样当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径距离。

          接下来如何找出最短路径?需借助辅助数组Path:同时借助[栈或队列或数组]。path[i][j] =k表示最短路径i-…j 和j的直接前驱为k,此时初始化是path[i][j]=i,即是:i-->......-->k ->j举例:如1-> 5->4  4->3->6 ,此时path[1][6]=0;0表示1->6不通。当我们引入节点k = 4此时有1->5->4->3->6,显然有paht[1][6] = 3 = paht[4][6] =paht[k][6],如是有 path[i][j] =path[k][j] 。对于1->5相邻边,我们可以在初始化时候 有 paht[1][5]=1;如是对于最短路径1->5->4->3->6有paht[1][6] = 3; paht[1][3]= 4;paht[1][4] = 5; paht[1][5] =1 如此逆推不难得到最短路径记录值。

     1 void Init_Floyd(void)
     2 {
     3     for(int i=0;i<MG->n;i++)
     4         for(int j=0;j<MG->n;j++)
     5         {
     6             if(i == j)
     7             {
     8                 dis[i][i]=0;
     9                 path[i][i]=i;
    10             }
    11             else
    12             {
    13                 dis[i][j]=MG->edge[i][j];
    14                 if(dis[i][j] == INF)
    15                     path[i][j]=-1;
    16                 else
    17                     path[i][j]=i;  //记录j的前驱节点
    18             }
    19         }
    20 }
    21 void Floyd(void)
    22 {
    23     int i,j,k;
    24 
    25     for(k=0;k<MG->n;k++)
    26     {
    27         for(i=0;i<MG->n;i++)
    28             for(j=0;j<MG->n;j++)
    29                 if((dis[i][k]>0 && dis[i][k]<INF) &&   //防止加法溢出 
    30                       (dis[k][j]>0 && dis[k][j]<INF) &&
    31                         dis[i][k] +dis[k][j] < dis[i][j])
    32                 {
    33                     dis[i][j]=dis[i][k] +dis[k][j];
    34                     path[i][j]=path[k][j];  //记录j的直接前驱k
    35                 }
    36     }
    37 }
     1 // 路径查询
     2 void SearchPath(int from,int to)
     3 {
     4     int min_path[MAXL],tot=0;
     5     int index_temp; //缓存索引
     6 
     7     min_path[tot++]=to;
     8     index_temp=path[from][to];
     9     while(index_temp != from)  //回溯找到源点
    10     {
    11         min_path[tot++]=index_temp;
    12         index_temp=path[from][index_temp];
    13     }
    14     min_path[tot]=from;
    15 
    16     printf("%c",MG->vertex[from]);  //对辅助数组进行逆向输出
    17     for(int i=tot-1;i>=0;i--)
    18         printf("->%c",MG->vertex[min_path[i]]);
    19 }
    ---  纵使山重水复,亦会柳暗花明   sunqh1991@163.com   欢迎关注,互相交流
  • 相关阅读:
    BZOJ1040: [ZJOI2008]骑士
    Codeforces 849D.Rooter's Song
    POJ4852 Ants
    NOIP模拟赛 17.10.10
    Codeforces 851D Arpa and a list of numbers
    BZOJ2529: [Poi2011]Sticks
    BZOJ1826: [JSOI2010]缓存交换
    POJ3579 Median
    codevs1214 线段覆盖
    POJ2230 Watchcow
  • 原文地址:https://www.cnblogs.com/wjcx-sqh/p/5929919.html
Copyright © 2011-2022 走看看