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

Posted elegantcloud

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构/PTA-旅游规划/图/dijkstra算法相关的知识,希望对你有一定的参考价值。

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

输入格式:

输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2N500)是城市的个数,顺便假设城市的编号为0~(N?1);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++){}中

  

 






以上是关于数据结构/PTA-旅游规划/图/dijkstra算法的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-3627路径规划 分层图 + Dijkstra + spfa

PTA-数据结构 Dijkstra 城市间紧急救援

pta—紧急救援 (dijkstra)

PTA 7-35 城市间紧急救援(Dijkstra+DFS)

PTA 紧急救援 /// dijkstra 最短路数 输出路径

DS06--图