Dijkstra

//在这里采用两种方式实现Dijkstra算法,经过测试两种方式:第一种:通过Dist【】让每一个顶点中Dist[]中寻找最短路径的点;第二种方式:从已经收录的顶点的相邻顶点中选择出最短路//径的的顶点,此种方式适合用于稠密图,减少点的遍历。

#include<iostream>
 #include<malloc.h>
 using namespace std;
 #define INF (100000)

 //相连顶点的信息
 typedef struct AdjNode{
    int Weight;
    int CostValue;
    int Adj;
    AdjNode *next;
AdjNode():Weight(NULL),CostValue(NULL),next(NULL){};
 }PtrToAdjVNode;

 //表头信息,每个表头的节点必须要进行标记,对表头进行标记
 typedef struct Vnode{
     PtrToAdjVNode *FirstEdge;
     int Flag;
 }AdjLink[10];

 typedef struct AdjGraph{
 int VerterNum;
 int EdgeNum;
 AdjLink LG;
 }LGraph;

 LGraph *Graph=new LGraph;
 void Insert(int A,int B,int C,int D)
 {
    PtrToAdjVNode *Ptr=new PtrToAdjVNode,*Rear;
    Ptr->Adj=B;
    Ptr->Weight=C;Ptr->CostValue=D;Ptr->next=NULL;
    if(!Graph->LG[A].FirstEdge)
    {
        Graph->LG[A].FirstEdge=Ptr;
    }
    else
    {
        Rear=Graph->LG[A].FirstEdge;
        while(Rear->next!=NULL)
        {
            Rear=Rear->next;
        }
        Rear->next=Ptr;
    }
 }
void CreateGraph(int VerNum,int EdgeNum)
 {//顶点从0开始
     int i;Graph->VerterNum=VerNum;Graph->EdgeNum=EdgeNum;
         for(i=0;i<VerNum;i++)
         {
             Graph->LG[i].Flag=NULL;
             Graph->LG[i].FirstEdge=NULL;
         }
         int NN,MM,KK,CC;
         for(i=0;i<EdgeNum;i++)
         {
            cin>>NN>>MM>>KK>>CC;
            Insert(NN,MM,KK,CC);
         }
 }

 int Get_Weight(int Start,int FindNum)
 {
     PtrToAdjVNode *Rear=Graph->LG[Start].FirstEdge;
     int Value=INF;
     if(Start==FindNum)
         return 0;
     while(Rear)
     {
         if(Rear->Adj==FindNum)

             {
                        Value=Rear->Weight;
                        break;
            }
         else
         {
             Rear=Rear->next;
         }

     }
     return Value;
 }
 void Search(int prev[],int Start,int end)
 {
    //简单摆Dijkstra算法遍历
     int i=end,j=0;int *rev=new int[Graph->VerterNum];
     //倒序的路径
     for(i=end;i!=Start;i=prev[i])
     {
        cout<<"["<<i<<"] ";
        rev[j++]=i;
     }
     cout<<i<<endl;
 }

 void Dijkstra(int dist1[],int prev1[],int Vstart,int Vend)
 {
    //防止出现两条相等路径,最外面只将从Start---End点上的最短路径上顶点在表头上标记
     //最外面只标记最短路径,最好只标记与顶点相邻的分叉点
     /***第一步计算出S点与相邻点的dist,同时初始化*/
     int prev[10],dist[10],flag[10];
     int i;//int *flag=new int[Graph->VerterNum];
     for(i=0;i<Graph->VerterNum;i++)
     {

        flag[i]=0;
        dist[i]=Get_Weight(Vstart,i);//只能够得到他么最短路径
        if(dist[i]<INF)
            prev[i]=Vstart;
        else
            prev[i]=-1;
     }
     //接下来是Dijkstra 核心,从U集合中选取一个最短路径的点加入S集合
     //同时更新比较经过k 点与不经过K点到k 的相邻点上距离。

     prev[Vstart]=Vstart;flag[Vstart]=1;
     int m,n,kIndex,j;
     int MIndex=Vstart;
     int Min,Tmp; int Min1=INF,K1;

     for(m=0;m<Graph->VerterNum;m++)//大循环保证每个点都能遍历
     {
         Min=INF;Min1=INF;
        //从U中挑选出离S集合最近的点,通过比较,将各个顶点与S中点相比较
         for(n=0;n<Graph->VerterNum;n++)
         {
             //从没有遍历的点中找到最短路径的点

             if(Graph->LG[n].FirstEdge &&Graph->LG[n].Flag==false && !flag[n] )
             {
                 if(dist[n]<Min)
                 {
                     Min=dist[n];
                     kIndex=n;
                 }
             }
         }
         /**上面步骤主要是从相近点中找到最短路径的点,dist存储各个点情况,只有路径就可以到达,保证找到最终点*/
         //如果找到最终点刚好在最短路径上,可以用之下方法
         //只从点的相邻点中找路径,flag表示已经遍历dist存储各个点情况
         PtrToAdjVNode *Rear=Graph->LG[MIndex].FirstEdge; //从相邻点中找最短路径,保证最终点在路径上,但是找出图中最短的点
         while(Rear)
         {
             if(flag[Rear->Adj]==0)
             {
                 if(dist[Rear->Adj]<Min1)
                 {
                     Min1=dist[Rear->Adj];
                     MIndex=Rear->Adj;
                 }
             }
             Rear=Rear->next;
         }
          flag[MIndex]=1;

         //不断更新dist同prev
        for(j=0;j<Graph->VerterNum;j++)
        {
            Tmp=Get_Weight(MIndex,j);

                Tmp=(Tmp==INF)?INF:(Min1+Tmp);

                if(!flag[j] && Graph->LG[j].Flag==false && dist[j]>Tmp)//只有在修改时候才能进行prev修改
                {    dist[j]=Tmp;
                    prev[j]=MIndex;
                }
            }

        }
     //对路径的回溯
     Search(prev,Vstart,Vend);

         }

 int main()
 {
    int VerNum,EdgeNum,VerStart,Verend;
    cin>>VerNum>>EdgeNum>>VerStart>>Verend;
    CreateGraph(VerNum,EdgeNum);

    //选择出最短路径,如果有相同最短路径在计算出最小花费
    int *dist=new int[VerNum]; int *prev=new int[VerNum];
    Dijkstra(dist,prev,VerStart,Verend);
 return 0;
 }

现在只是解决了最短路径的问题,单路径中出现相等路径怎么用Dijkstra算法计算出相同不同顶点有相同路径算法。

下面这个算法针对计算多条路径:方法,在表头列表中增加一项Prev,记录遍历整个的过程,特别记录到达某点时候dist[i]=Tmp 处值,在这里最有可能会发生相同路径的特需点

模拟图

在列表prev中贮存Start到此点中最短路径的前一个点

#include<iostream>
 #include<malloc.h>
 using namespace std;
 #define INF (100000)

 //相连顶点的信息
 typedef struct AdjNode{
    int Weight;
    int CostValue;
    int Adj;
    AdjNode *next;
AdjNode():Weight(NULL),CostValue(NULL),next(NULL){};
 }PtrToAdjVNode;

 //表头信息,每个表头的节点必须要进行标记,对表头进行标记
 typedef struct Vnode{
     PtrToAdjVNode *FirstEdge;
     int prev[5];//记录与此节点距离最近的父节点
     int pcnt;
 }AdjLink[10];

 typedef struct AdjGraph{
 int VerterNum;
 int EdgeNum;
 AdjLink LG;
 }LGraph;

 LGraph *Graph=new LGraph;
 void Insert(int A,int B,int C,int D)
 {
    PtrToAdjVNode *Ptr=new PtrToAdjVNode,*Rear;
    Ptr->Adj=B;
    Ptr->Weight=C;Ptr->CostValue=D;Ptr->next=NULL;
    if(!Graph->LG[A].FirstEdge)
    {
        Graph->LG[A].FirstEdge=Ptr;
    }
    else
    {
        Rear=Graph->LG[A].FirstEdge;
        while(Rear->next!=NULL)
        {
            Rear=Rear->next;
        }
        Rear->next=Ptr;
    }
 }
void CreateGraph(int VerNum,int EdgeNum)
 {//顶点从0开始
     int i;Graph->VerterNum=VerNum;Graph->EdgeNum=EdgeNum;
         for(i=0;i<VerNum;i++)
         {
             Graph->LG[i].pcnt=NULL;
             Graph->LG[i].FirstEdge=NULL;
             memset(Graph->LG[i].prev,-1,sizeof(int)*5);
         }
         int NN,MM,KK,CC;
         for(i=0;i<EdgeNum;i++)
         {
            cin>>NN>>MM>>KK>>CC;
            Insert(NN,MM,KK,CC);
         }
 }

 int Get_Weight(int Start,int FindNum)
 {
     PtrToAdjVNode *Rear=Graph->LG[Start].FirstEdge;
     int Value=INF;
     if(Start==FindNum)
         return 0;
     while(Rear)
     {
         if(Rear->Adj==FindNum)

             {
                        Value=Rear->Weight;
                        break;
            }
         else
         {
             Rear=Rear->next;
         }

     }
     return Value;
 }
 void Search(int prev[],int Start,int end)
 {
    //简单摆Dijkstra算法遍历
     int i=end,j=0;int *rev=new int[Graph->VerterNum];
     //倒序的路径
     for(i=end;i!=Start;i=prev[i])
     {
        cout<<"["<<i<<"] ";
        rev[j++]=i;
     }
    cout<<"["<<i<<"] ";
    rev[j]=Start;

    int pathCost=0;
    PtrToAdjVNode *Rear;int K=1;
    while(j>0)
    {
        Rear=Graph->LG[rev[j]].FirstEdge;

        if(Rear->next && K)
        {//防止出现双等路径,只标记第一个路径上,这种方式不行的
            //Graph->LG[rev[j]].Flag=true;
            K=0;

        }

        while(Rear)
        {
            if(rev[j-1]==Rear->Adj)
            {
                pathCost+=Rear->CostValue;
                break;
            }
            else
            {
                Rear=Rear->next;
            }
        }
        j=j-1;
    }
    cout<<"最短路径上花费"<<pathCost<<endl;

 }
 int Calculate(int A,int B)
 {//计算出两个地图之间花费
     PtrToAdjVNode *Rear=Graph->LG[A].FirstEdge;
     int SiglePath=0;
    while(Rear)
    {
        if(B==Rear->Adj)
            {
                SiglePath=Rear->CostValue;
                break;
            }
            else
            {
                Rear=Rear->next;
            }
    }
    return SiglePath;
 }
 void PathCost(int start,int end)
 {
 //多条相等路径,比较相同同时对其进行
     int Trarget=end,Trarget1;
     int *path=new int[Graph->VerterNum];
     int i=0;int cost=0;
     while (Trarget!=start)
     {
         path[i++]=Trarget;
         if(Graph->LG[Trarget].pcnt==1)
         {

             Trarget1=Graph->LG[Trarget].prev[0];
             cost+=Calculate(Graph->LG[Trarget].prev[0],Trarget);
             Trarget=Trarget1;
         }
         else
         {
             //从一系列相等的之中挑选出最小花费路径
            // path[i++]=Trarget;
             int MinINf=INF,Tp;
             for(int j=0;j<Graph->LG[Trarget].pcnt;j++)
             {
                 Tp=Calculate(Graph->LG[Trarget].prev[j],Trarget);
                 if(Tp<MinINf)
                 {
                    MinINf=Tp;

                    Trarget1=Graph->LG[Trarget].prev[j];
                 }
             }
             cost+=MinINf;
             Trarget=Trarget1;
         }

     }
     path[i]=start;
     cout<<"多条相等路径中花费最小前:"<<cost<<endl;
     for(;i>=0;i--)
     {
     cout<<"["<<path[i]<<"] ";
     }

 }
 void Dijkstra(int dist1[],int prev1[],int Vstart,int Vend)
 {
    //防止出现两条相等路径,最外面只将从Start---End点上的最短路径上顶点在表头上标记
     //最外面只标记最短路径,最好只标记与顶点相邻的分叉点
     /***第一步计算出S点与相邻点的dist,同时初始化*/
     int prev[10],dist[10],flag[10];
     int i;//int *flag=new int[Graph->VerterNum];
     for(i=0;i<Graph->VerterNum;i++)
     {

        flag[i]=0;
        dist[i]=Get_Weight(Vstart,i);//只能够得到他么最短路径
        if(dist[i]<INF)
        {    prev[i]=Vstart;
        Graph->LG[i].prev[Graph->LG[i].pcnt++]=Vstart;
         }
        else
            prev[i]=-1;
     }
     //接下来是Dijkstra 核心,从U集合中选取一个最短路径的点加入S集合
     //同时更新比较经过k 点与不经过K点到k 的相邻点上距离。

     prev[Vstart]=Vstart;flag[Vstart]=1;
     int m,n,kIndex,j;
     int MIndex=Vstart;
     int Min,Tmp; int Min1=INF,K1;

     for(m=0;m<Graph->VerterNum;m++)//大循环保证每个点都能遍历
     {
         Min=INF;Min1=INF;
        //从U中挑选出离S集合最近的点,通过比较,将各个顶点与S中点相比较
         for(n=0;n<Graph->VerterNum;n++)
         {
             //从没有遍历的点中找到最短路径的点

             if(Graph->LG[n].FirstEdge  && !flag[n] )
             {
                 if(dist[n]<Min)
                 {
                     Min=dist[n];
                     kIndex=n;
                 }
             }
         }
         /**上面步骤主要是从相近点中找到最短路径的点,dist存储各个点情况,只有路径就可以到达,保证找到最终点*/
         //如果找到最终点刚好在最短路径上,可以用之下方法
         //只从点的相邻点中找路径,flag表示已经遍历dist存储各个点情况
         PtrToAdjVNode *Rear=Graph->LG[MIndex].FirstEdge; //从相邻点中找最短路径,保证最终点在路径上,但是找出图中最短的点
         while(Rear)
         {//缺点,如果算多条相等路径,无法计算出来
             if(flag[Rear->Adj]==0)
             {
                 if(dist[Rear->Adj]<Min1)
                 {
                     Min1=dist[Rear->Adj];
                     MIndex=Rear->Adj;
                 }
             }
             Rear=Rear->next;
         }
          flag[kIndex]=1;

         //不断更新dist同prev
        for(j=0;j<Graph->VerterNum;j++)
        {
            Tmp=Get_Weight(kIndex,j);

                Tmp=(Tmp==INF)?INF:(Min+Tmp);

                if(!flag[j]  && dist[j]>Tmp)//只有在修改时候才能进行prev修改
                {
                    dist[j]=Tmp;
                    prev[j]=kIndex;
                    Graph->LG[j].prev[Graph->LG[j].pcnt++]=kIndex;
                }
                else if(dist[j]==Tmp && dist[j]!=INF && !flag[j] && kIndex!=j)
                {
                    Graph->LG[j].prev[Graph->LG[j].pcnt++]=kIndex;
                    flag[kIndex]=1;
                }
            }

        }
     //对路径的回溯

     Search(prev,Vstart,Vend);
     //多条相等的路径存取在头列表中如何对其进行遍历
     PathCost(Vstart,Vend);

         }

 int main()
 {
    int VerNum,EdgeNum,VerStart,Verend;
    cin>>VerNum>>EdgeNum>>VerStart>>Verend;
    CreateGraph(VerNum,EdgeNum);

    //选择出最短路径,如果有相同最短路径在计算出最小花费
    int *dist=new int[VerNum]; int *prev=new int[VerNum];
        Dijkstra(dist,prev,VerStart,Verend);
 return 0;
 }

时间: 2024-10-23 18:39:54

Dijkstra的相关文章

畅通project续HDU杭电1874【dijkstra算法 || SPFA】

http://acm.hdu.edu.cn/showproblem.php?pid=1874 Problem Description 某省自从实行了非常多年的畅通project计划后.最终修建了非常多路.只是路多了也不好,每次要从一个城镇到还有一个城镇时,都有很多种道路方案能够选择,而某些方案要比还有一些方案行走的距离要短非常多.这让行人非常困扰. 如今,已知起点和终点,请你计算出要从起点到终点.最短须要行走多少距离. Input 本题目包括多组数据.请处理到文件结束. 每组数据第一行包括两个正

Choose the best route 【Dijkstra】

Problem DescriptionOne day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend's home as soon as possible . Now give you a map of the city's traffic route, and the stations which are near Kiki

Bus System 【dijkstra算法】

Because of the huge population of China, public transportation is very important. Bus is an important transportation method in traditional public transportation system. And it's still playing an important role even now.The bus system of City X is qui

ACM: HDU 2544 最短路-Dijkstra算法

HDU 2544最短路 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据.每组数据第一行是两个整数N.M(N<=100,M<

ACM: HDU 3790 最短路径问题-Dijkstra算法

HDU 3790 最短路径问题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的. Input 输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p.最后一行是

dijkstra堆优化模板

1 #include<iostream> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<queue> 7 #define inf 2147483647 8 using namespace std; 9 struct data 10 { 11 int from,to,next,w; 12 data(){f

邻接表实现Dijkstra算法以及DFS与BFS算法

//============================================================================ // Name : ListDijkstra.cpp // Author : fffff // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //==========================

Dijkstra算法(求解单源最短路)详解 + 变形 之 poj 1860 Currency Exchange

/* 求解单源最短路问题:Dijkstra算法(该图所有边的权值非负) 关键(贪心): (1)找到最短距离已经确定的节点,从它出发更新与其相邻节点的最短距离: (2)此后不再关心(1)中“最短距离已经确定的节点”. 时间复杂度(大概的分析,不准确): “找到最短距离已经确定的节点” => O(|V|) "从它出发更新与其相邻节点的最短距离" => 邻接矩阵:O(|V|),邻接表:O(|E|) 需要循环以上两个步骤V次,所以时间复杂度:O(V^2) 即:在|E|较小的情况下,

Dijkstra 算法

最短路径算法的基础知识,参见 http://blog.csdn.net/pacosonswjtu/article/details/49894021 Dijkstra算法 涉及到的 优先队列的操作实现(该优先队列的数据类型不是 int , 而是 Distance),详情参见http://blog.csdn.net/pacosonswjtu/article/details/49923389 [1]Dijkstra 算法相关 1.1)贪婪算法一般分阶段去求解一个问题, 在每个阶段它都把当前出现的当做是