最短路 记录路径

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <p><span style="font-size: 18px;">最短路主要有四部分。</span></p><p><span style="font-size: 18px;"><span style="white-space: pre;"></span></span><span style="font-family: Arial, Helvetica, sans-serif;">迪杰斯特拉思想</span></p>  
[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //Dijkstra算法用于计算一个节点到其它所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点。  
  2. //基本思想是:设置顶点集合S不断地做贪心选择来扩充这个集合  
  3. //初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。  
  4.   
  5.   
  6. #include <stdio.h>  
  7. #define maxnum 100  
  8. #define maxint 999999  
  9.   
  10. int dist[maxnum]; //表示当前点到源点的最短路径长度  
  11. int prev[maxnum];   //记录当前点的前一个结点  
  12. int c[maxnum][maxnum];  //记录图的两点间路径长度  
  13. int n,line;            //图的结点数和路径数  
  14.   
  15.   
  16. void Dij(int n,int v,int *dist, int *prev, int c[maxnum][maxnum]) //v代表源点吗?  
  17. {  
  18.     int s[maxnum] = {0};//判断是否已将该点存入到s数组中  
  19.     int i;  
  20.     for(i = 1;i<=n;i++)  
  21.     {  
  22.         dist[i] = c[v][i];//将从源点到i点的初始距离存入数组dist中  
  23.         s[i] = 0;//初始化为全部没有用过该点  
  24.         if(dist[i] == maxint)//如果源点到该点的距离为无穷大,则该点前面没有连接点  
  25.             prev[i] = 0;  
  26.         else  
  27.             prev[i] = v;  
  28.     }  
  29.     dist[v] = 0;    //源点到源点的距离初始化为0  
  30.     s[v] = 1;//把源点存入数组s  
  31.       
  32.     //依次将未放入集合s中的节点,取dist【】最小值的节点放进去  
  33.     //一旦s包含了所有v中顶点,dist就记录了从源点到所有其他顶点之间的最短路径  
  34.     //注意是从第二个节点开始,第一个结点表示源点  
  35.    for(i = 2;i<=n;i++)  
  36.    {  
  37.        int tmp = maxint;  
  38.        int u = v;  
  39.        for(int j = 1;j<=n;j++)  //找出当前未使用的点j的dist【j】最小值  
  40.        {  
  41.            if((!s[j]) && dist[j] < tmp)  
  42.            {  
  43.                u = j;               //u储存当前邻接点中距离最小的点的号码  
  44.                tmp = dist[j];  
  45.            }  
  46.        }  
  47.        s[u] = 1;        //一次for循环结束后,便找出了所有未使用的点中距离最小的点,将此点存入集合s中  
  48.          
  49.        //更新dist值  
  50.          
  51.        for(int j = 1;j<=n;j++)  
  52.        {  
  53.            if((!s[j]) && c[u][j]<maxint) //确定该点没有加入s集合,并且存在这段距离,即经过该点  
  54.            {  
  55.                int newdist = dist[u] + c[u][j];//判断经过该点到j的距离和不经过该点到j的距离的大小  
  56.                if(newdist < dist[j])  
  57.                {  
  58.                    dist[j] = newdist;  
  59.                    prev[j] = u;  
  60.                }  
  61.            }  
  62.        }  
  63.    }  
  64. }  
  65.   
  66. //查找从源点v到终点u的路径,并输出  
  67.   
  68. void searc(int *prev,int v,int u)  
  69. {  
  70.     int que[maxnum];        //该数组保存路径  
  71.     int tot = 1;  
  72.     que[tot] = u;       //从终点开始找,一直找到源点v并记录路径  
  73.     tot++;  
  74.     int tmp = prev[u];  
  75.     while(tmp != v)  
  76.     {  
  77.         que[tot] = tmp;  
  78.         tot++;  
  79.         tmp = prev[tmp];  
  80.     }  
  81.     que[tot] = v;  
  82.     for(int i = tot;i>=1;i--)//输出  
  83.     {  
  84.         if(i!=1)  
  85.             printf("%d->",que[i]);  
  86.         else  
  87.             printf("%d\n",que[i]);  
  88.     }  
  89.     //注意,若题目要求输出距离,则直接输出dist【u】即可  
  90. }  
  91.   
  92. int main()  
  93. {  
  94.     scanf("%d%d",&n,&line);  
  95.     int p,q,len;  
  96.     for(int i = 1;i<=n;i++)  
  97.     {  
  98.         for(int j = 1;j<=n;j++)  
  99.             c[i][j] = maxint;  
  100.     }  
  101.     for(int i = 1;i<=line;i++)  
  102.     {  
  103.         dist[i] = maxint;  
  104.     }  
  105.     for(int i = 1;i<=line;i++)  
  106.     {  
  107.         printf("%d%d%d",&p,&q,&len);  
  108.         if(len<c[p][q])  
  109.         {  
  110.             c[p][q] = len;  
  111.             c[q][p] = len;  
  112.         }  
  113.     }  
  114.     for(int i = 1;i<=n;i++)  
  115.     {  
  116.         for(int j = 1;j<=n;j++)  
  117.         {  
  118.             printf("%8d",c[i][j]);  
  119.         }  
  120.         printf("\n");  
  121.     }  
  122.     Dij(n,1,dist,prev,c);  
  123.     printf("从源点到终点的最短路径长度为%d\n",dist[n]);  
  124.     searc(prev,1,n);  
  125.     return 0;  
  126. }  
[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //下面运用弗洛伊德(Floyd)来解决有关问题  
  2. //在该思想中,数组a【】【】初始化为个顶点之间的距离,最后储存各定点之间的最短距离。  
  3. //path【】【】数组保存最短路径,与当前迭代的次数有关,初始化都为-1,即没有中间顶点。  
  4. //在求a【i】【j】的过程中,path[i][j]存放从顶点i到顶点j的中间顶点的编号不大于k的最短路径上前一个结点的编号  
  5. //数组a[][]其实是有向图的邻接矩阵,此类矩阵可以表示无向  
  6.   
  7.   
  8. //这个程序是  
  9. #include <stdio.h>  
  10. #include <string.h>  
  11.   
  12.   
  13. struct MGraph  
  14. {  
  15.     char vertex[1000];      // 储存各个顶点  
  16.     int edges[1000][1000];      //邻接矩阵  
  17.     int n,e; // n代表顶点个数,e代表边数  
  18. };  
  19.   
  20.   
  21. void ppath(int path[][1000],int i,int j)   调用函数,输出路径  
  22. {  
  23.     int k;  
  24.     k = path[i][j];  
  25.     if(k == -1)  
  26.         return;  
  27.     ppath(path,i,k);  
  28.     printf("%d,",k);  
  29.     ppath(path,k,j);  
  30. }  
  31.   
  32.   
  33. void CreateMGraph(MGraph &G)  
  34. {  
  35.     int i,j,k,p;  
  36.     scanf("%d%d",&G.n,&G.e);    //输入顶点数和边数  
  37.     for(i = 0;i<G.n;i++)        //输入各个顶点  
  38.     {  
  39.         scanf("%d",&G.vertex[i]);  
  40.     }  
  41.     for(i = 0;i<G.n;i++) // 初始化邻接矩阵。若是对角线,即是自己到自己的距离,初始化为0  
  42.     {  
  43.         for(j = 0;j<G.n;j++)  
  44.         {  
  45.             G.edges[i][j] = 100000;  
  46.             if(i == j)  
  47.                 G.edges[i][j] = 0;  
  48.         }  
  49.     }  
  50.     for(i = 0;i<G.e;i++) // 输入边的前驱后驱以及权值  
  51.     {  
  52.         scanf("%d%d%d",&j,&k,&p);  
  53.         G.edges[j][k] = p;  
  54.     }  
  55. }  
  56.   
  57.   
  58. void Dispath(int A[][1000],int path[][1000],int n)  
  59. {  
  60.     int i,j;  
  61.     for(i = 0;i<n;i++)  
  62.     {  
  63.         for(j = 0;j<n;j++)  
  64.         {  
  65.             if(A[i][j] == 100000)  
  66.             {  
  67.                 if(i!=j)  
  68.                     printf("从%d到%d没有路径\n",i,j);  
  69.             }  
  70.             else  
  71.             {  
  72.                 printf("从%d到%d=>路径长度:%d路径:",i,j,A[i][j]);  
  73.                 printf("%d",i);  
  74.                 ppath(path,i,j);  
  75.                 printf("%d\n",j);  
  76.             }  
  77.         }  
  78.     }  
  79. }  
  80.   
  81.   
  82. void Floyd(MGraph &G)  
  83. {  
  84.     int A[1000][1000],path[1000][1000];  
  85.     int i,j,k;  
  86.     //初始化a【】【】为最开始的距离,path【】【】代表最短路径,与当前迭代的次数有关  
  87.     for(i = 0;i<G.n;i++)  
  88.     {  
  89.         for(j = 0;j<G.n;j++)  
  90.         {  
  91.             A[i][j] = G.edges[i][j];  
  92.             path[i][j] = -1;  
  93.         }  
  94.     }  
  95.     for(k = 0;k<G.n;k++)// 运用弗洛伊德进行最短路搜索,k作为中间点  
  96.     {  
  97.         for(i = 0;i<G.n;i++)  
  98.         {  
  99.             for(j = 0;j<G.n;j++)  
  100.             {  
  101.                 if(A[i][j] > A[i][k] + A[k][j])  
  102.                 {  
  103.                     A[i][j] = A[i][k] + A[k][j];  
  104.                     path[i][j] = k;  
  105.                 }  
  106.             }  
  107.         }  
  108.     }  
  109.     Dispath(A,path,G.n);  
  110. }  
  111.   
  112.   
  113.   
  114.   
  115. int main()  
  116. {  
  117.     MGraph G;  
  118.     CreateMGraph(G);  
  119.     Floyd(G);  
  120.     return 0;  
  121. }  
[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. </pre><pre code_snippet_id="204097" snippet_file_name="blog_20140225_5_5274998" name="code" class="html">  
[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. </pre><pre code_snippet_id="204097" snippet_file_name="blog_20140225_5_5274998" name="code" class="html">  

贝尔曼—福特思想

[html]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //迪杰斯特拉算法是处理单源最短路径的算法,但它局限于边的权值非负的情况  
  2. //贝尔曼——福特就可以解决此类问题  
  3. //思想:给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,  
  4.   
  5. //数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0;  
  6.    
  7. //以下操作循环执行至多n-1次,n为顶点数:  
  8. //对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;  
  9. //若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;  
  10. //为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,  
  11. //即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。  
  12.   
  13.   
  14. #include <stdio.h>  
  15. #include <stdlib.h>  
  16. #define maxnum 2000  
  17. #define maxint 999999  
  18.   
  19. typedef struct  
  20. {  
  21.     int v,u;        //终点和起点  
  22.     int weight;     //两点之间的权值  
  23. } Edge;  
  24. Edge edge[maxnum];      //保存边的值  
  25. int dist[maxnum];       //保存结点到原点的最短距离  
  26.   
  27. int nodenum,edgenum,source;     //结点数,边数,源点  
  28.   
  29. void init()  
  30. {  
  31.     scanf("%d%d%d",&nodenum,&edgenum,&source);  //输入结点数,边数,源点  
  32.     int i;  
  33.     for(i = 1;i <= nodenum;i++)  
  34.         dist[i] = maxint;       //把结点到原点的距离都初始化为最大  
  35.         dist[source] = 0;       //节点到节点的距离初始化为0  
  36.         for(i = 1;i<=edgenum;i++)  
  37.         {  
  38.             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].weight);  //点u到点v的距离  
  39.             if(edge[i].u == source)  
  40.                 dist[edge[i].v] = edge[i].weight;       //如果起点是源点,则把点v到点u(源点)的距离更改为权值weight  
  41.         }  
  42. }  
  43. int BF()        //该函数用于计算最小距离和判断是否有负权值  
  44. {  
  45.     int i,j,flag = 1;  
  46.     for(i = 1;i<=nodenum-1;i++) //外层循环的次数是结点数减一  
  47.     {  
  48.         for(j = 1;j <= edgenum;j++)//内层循环是边的数目,也就是每次都遍历整个边表  
  49.         {  
  50.             if(dist[edge[j].v] > dist[edge[j].u] + edge[j].weight)  
  51.                 dist[edge[j].v] = dist[edge[j].u] + edge[j].weight;  
  52.                 //如果从源点到第v个点的距离大于从源点到第u个点的距离加上从u点到v点的距离,就改变从源点到第v个点的距离  
  53.         }  
  54.     }  
  55.     for(i = 1;i<=edgenum;i++)      //再一次进行最短路搜寻,在上面的循环中已经求出了最短路线,如果还能求出最短路线,则会出现负环路,每进去一次,都会减小  
  56.     {  
  57.         if(dist[edge[i].v > dist[edge[i].u + edge[i].weight)  
  58.         {  
  59.             flag=0;  
  60.             break;  
  61.         }  
  62.     }  
  63.     return flag;  
  64. }  
  65. int main()  
  66. {  
  67.     init();  
  68.     if(BF())  
  69.     {  
  70.         for(int i = 1;i<=nodenum;i++)  
  71.             printf("%d\n",dist[i]);  
  72.     }  
  73.     else  
  74.         printf("-1\n");  
  75.     return 0;  
  76. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值