• 数据结构/PTA-旅游规划/图/dijkstra算法


    有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

    输入格式:

    输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2N500)是城市的个数,顺便假设城市的编号为0~(N1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

    输出格式:

    在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

    输入样例:

    4 5 0 3
    0 1 1 20
    1 3 2 30
    0 3 4 10
    0 2 2 20
    2 3 1 20
    

    输出样例:

    3 40

    #include<bits/stdc++.h>
    using namespace std;
    struct
    {
        int pos;
        int len;
        int cost;
    } visit[520]; //起点到i点的各项数值
    struct
    {
        int len;
        int cost;
    } graph[520][520]; //i点到j点的各项数值
    void initgraph(int N)
    {
        for(int i=0; i<=N; i++)
            for(int j=0; j<=N; j++)
            {
                graph[i][j].cost=9999;
                graph[i][j].len=9999;
            }
    }
    //N M S D//城市个数,公路条数,始点,终点
    void initvisit(int N,int S)
    {
        for(int i=0; i<=N; i++)
        {
            visit[i].pos=0;
            visit[i].len=graph[i][S].len;
            visit[i].cost=graph[i][S].cost;
        }
        //起点到起点本身的各项数值
        visit[S].pos=1;
        visit[S].cost=0;
        visit[S].len=0;
    }
    int dij(int N,int S)
    {
        int i,j,k;
        for(j=0; j<N; j++)
        {
            int minpos=N;
            for(i=0; i<N; i++)
            {
                if(!visit[i].pos&&visit[i].len<visit[minpos].len)
                {
                    minpos=i;
                }
            }
            if(minpos==N)
                break;
            visit[minpos].pos=1;
            for(int i=0; i<N; i++)
            {
                if(!visit[i].pos)
                {
                    if(visit[i].len > visit[minpos].len + graph[i][minpos].len)
                    {
                        visit[i].len = visit[minpos].len + graph[i][minpos].len;
                        visit[i].cost = visit[minpos].cost + graph[i][minpos].cost;
                    }
                    if(visit[i].len==visit[minpos].len + graph[i][minpos].len)
                    {
                        if(visit[i].cost>visit[minpos].cost + graph[i][minpos].cost)
                            visit[i].cost=visit[minpos].cost + graph[i][minpos].cost;
                    }
                }
            }
        }
    }
    int main()
    {
        int N,M,S,D;
        cin>>N>>M>>S>>D;
        initgraph(N);
        int a,b,x,y;
        for(int i=0; i<M; i++)
        {
            cin>>a>>b>>x>>y;
            graph[a][b].len=x;
            graph[a][b].cost=y;
            graph[b][a].len=x;
            graph[b][a].cost=y;
        }
        initvisit(N,S);
        dij(N,S);
        cout<<visit[D].len<<" "<<visit[D].cost;
    }

    分析:单源路径最短问题

        简而言之,求两地之间最短距离的路径,若有多条一样短的路径,那么再找最便宜的

             

        如上图,是根据样例得到的图

        这就是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。直接使用迪杰斯特拉(Dijkstra)算法即可:

          
    设置辅助数组Dist,其中每个分量Dist[k]表示:当前所求得的从源点到其余各顶点k的最短路径。
    一般情况下:Dist[k]=<源点到顶点k的弧上的权值>或者=<源点到其它顶点的路径长度>+<其它顶点到顶点k的弧上的权值>
    其初态为:若从源点到顶点k有弧,则为弧上权值;
    否则,则为∞。
    1.在所有从源点出发的弧中选取一条权值最小的弧,即为第一条最短路径。 Dist[k]=v>G.arcs[v][k]v和k之间存在弧,INFINITEv和k之间不存在弧 其中的最小值即为最短路径的长度。 2. 修改其它各顶点的Dist[k]值。假设求得最短路径的顶点为u,若 Dist[u]+G.arcs[u][k]<Dist[k] 则将 Dist[k] 改为 Dist[u]+G.arcs[u][k]。 3. 在各顶点的Dist[k]中选择最小值,即为到达该顶点的最短路径。 4. 重复2,3步,直到所有顶点的最短路径都找到。
     

        对于本题的代码:

        1.定义结点和路径

           不再从图的标准结构设置,直接设置邻接矩阵的结构体。visit[]记录结果;graph[][]相当于图的弧,里面记录下标(结点)之间的长度、费用

    #include<bits/stdc++.h>
    using namespace std;
    struct
    {
        int pos;
        int len;
        int cost;
    } visit[520]; //起点到i点的各项数值
    struct
    {
        int len;
        int cost;
    } graph[520][520]; //i点到j点的各项数值

      2.初始化

    void initvisit(int N,int S)
    {
        for(int i=0; i<=N; i++)
        {
            visit[i].pos=0;
            visit[i].len=graph[i][S].len;
            visit[i].cost=graph[i][S].cost;
        }
        //起点到起点本身的各项数值
        visit[S].pos=1;
        visit[S].cost=0;
        visit[S].len=0;
    }

      这里不要忘记N是城市个数,S是起点。初始化visit为源点外的其它点到源点距离,注意自己到自己的距离和费用都是0。

    3.数据的输入

        int N,M,S,D;
        cin>>N>>M>>S>>D;
        initgraph(N);
        int a,b,x,y;
        for(int i=0; i<M; i++)
        {
            cin>>a>>b>>x>>y;
            graph[a][b].len=x;
            graph[a][b].cost=y;
            graph[b][a].len=x;
            graph[b][a].cost=y;
        }

      不要忘记graph[a][b]和graph[b][a]都设置上

       4.核心:Dijkstra函数

    int dij(int N,int S)
    {
        int i,j,k;
        for(j=0; j<N; j++)
        {
            int minpos=N;
            for(i=0; i<N; i++)
            {
                if(!visit[i].pos&&visit[i].len<visit[minpos].len)
                {
                    minpos=i;
                }
            }
            if(minpos==N)
                break;
            visit[minpos].pos=1;
            for(int i=0; i<N; i++)
            {
                if(!visit[i].pos)
                {
                    if(visit[i].len > visit[minpos].len + graph[i][minpos].len)
                    {
                        visit[i].len = visit[minpos].len + graph[i][minpos].len;
                        visit[i].cost = visit[minpos].cost + graph[i][minpos].cost;
                    }
                    if(visit[i].len==visit[minpos].len + graph[i][minpos].len)
                    {
                        if(visit[i].cost>visit[minpos].cost + graph[i][minpos].cost)
                            visit[i].cost=visit[minpos].cost + graph[i][minpos].cost;
                    }
                }
            }
        }
    }

    ♦循环n-1次,找到这n-1个点中到源点最短的点,记为minpos(minpos的初始设为N)。判断条件:① !visit[i].pos :这个i点没有被使用过/没有被加入到最短路径中    ②Visit[i].len<Visit[MinPoint].len:源点到i的距离小于源点到minpos的距离

    visit[minpos].pos=1:这个点要被加入到最小路径中,赋1

    ♦是否存在位于源点和minpos之间的中继点,使得经过中继点的路长小于这两点直接路径的路长

      是,加入那个中继点,修改数据为新的路径

    是否存在位于源点和minpos之间的中继点,使得经过中继点的路长等于这两点直接路径的路长

      是,比较费用大小

    以上四个语段均放置在for(int j=1; j<N; j++){}中

      

  • 相关阅读:
    清理disuz垃圾用户信息SQL语句
    解决C++代码单元测试中的难题不可验证和IO调用
    开源分布式平台mooon系统结构
    只显示指定网卡IP地址命令
    优秀开源杀毒软件ClamAV
    pyenv本地安装python
    TCP/IP学习笔记:ARP
    [linux] 如何在vim里面把空格缩进改为tab缩进
    TCP/IP学习笔记:ICMP
    TCP/IP学习笔记:UDP
  • 原文地址:https://www.cnblogs.com/elegantcloud/p/13945507.html
Copyright © 2020-2023  润新知