最短路PTA

题目链接:https://pintia.cn/problem-sets/905631457273864192/problems/905631519127265289

 

题意:

 

本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。

输入格式:

输入在第一行给出两个正整数N(2 ≤ N ≤ 500)和M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:

V1 V2 one-way length time

其中V1V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1V2的单行线,则one-way为1,否则为0;length是道路的长度;time是通过该路所需要的时间。最后给出一对起点和终点的编号。

输出格式:

首先按下列格式输出最快到达的时间T和用节点编号表示的路线:

Time = T: 起点 => 节点1 => ... => 终点

然后在下一行按下列格式输出最短距离D和用节点编号表示的路线:

Distance = D: 起点 => 节点1 => ... => 终点

如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。

如果这两条路线是完全一样的,则按下列格式输出:

Time = T; Distance = D: 起点 => 节点1 => ... => 终点

输入样例1:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3

输出样例1:

Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3

输入样例2:

7 9
0 4 1 1 1
1 6 1 3 1
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 3 1
3 2 1 2 1
4 5 0 2 2
6 5 1 2 1
3 5

输出样例2:

Time = 3; Distance = 4: 3 => 2 => 5

 

代码:(迪杰斯特拉实现)

 

 

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include<malloc.h>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#define ri(n) scanf("%d",&n)
#define oi(n) printf("%d\n",n)
#define rl(n) scanf("%lld",&n)
#define ol(n) printf("%lld\n",n)
#define rep(i,l,r) for(i=l;i<=r;i++)
#define rep1(i,l,r) for(i=l;i<r;i++)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int epg=10-8;
const int maxn=1000;
int n,m,S,D;//顶点数,边数
int e[maxn][maxn],e2[maxn][maxn];
int vis[maxn],d[maxn],pathcount[maxn],path[maxn],ren[maxn],acount[maxn],v[maxn],v2[maxn],pathd[maxn];
void dijiesi1(int s,int t)
{
    for(int i=0; i<maxn; i++)
    {
        d[i]=inf;
        vis[i]=0;
        pathcount[i]=0;//在确保最短路的时候确保结点数最少
        path[i]=-1;//记录路径
    }
    d[s]=0;
    while(1)
    {
        int v=-1;
        for(int i=0; i<n; i++)
        {
            if(!vis[i]&&(v==-1||d[i]<d[v]))
                v=i;
        }
        if(v==-1)
            break;
        vis[v]=1;
        for(int i=0; i<n; i++)
        {
            if(!vis[i])
            {
                if(d[i]>d[v]+e[v][i])
                {
                    d[i]=d[v]+e[v][i];
                    path[i]=v;
                    pathcount[i]=pathcount[v]+1;//更新节点数
                }
                else if(d[i]==d[v]+e[v][i])//路长一样
                {
                    if(pathcount[i]>pathcount[v]+1)
                    {
                        pathcount[i]=pathcount[v]+1;//则取节点数少的那条边
                        path[i]=v;
                    }
                }
            }
        }
    }
}
void dijiesi2(int s,int t)
{
    for(int i=0; i<maxn; i++)
    {
        d[i]=inf;
        vis[i]=0;
        pathd[i]=0;//时间最快确保路径最短
        path[i]=-1;
    }
    d[s]=0;
    while(1)
    {
        int v=-1;
        for(int i=0; i<n; i++)
        {
            if(!vis[i]&&(v==-1||d[i]<d[v]))
                v=i;
        }
        if(v==-1)
            break;
        vis[v]=1;
        for(int i=0; i<n; i++)
        {
            if(!vis[i])
            {
                if(d[i]>d[v]+e2[v][i])
                {
                    d[i]=d[v]+e2[v][i];
                    path[i]=v;         //记录路径
                    pathd[i]=pathd[v]+e[v][i];     //更新路径长度
                }
                else if(d[i]==d[v]+e2[v][i])
                {
                    if(pathd[i]>pathd[v]+e[v][i])
                    {
                        //pathcount[i]=pathcount[v];
                        pathd[i]=pathd[v]+e[v][i];    //取路径长度小的
                        path[i]=v;
                    }
                }
            }
        }
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(e,inf,sizeof(e));
        memset(e2,inf,sizeof(e2));
        //memset(vis,0,sizeof(vis));
        //memset(d,inf,sizeof(d));
        memset(v,0,sizeof(v));
        memset(v2,0,sizeof(v2));
        for(int i=0; i<n; i++)
        {
            e[i][i]=0;
            e2[i][i]=0;
        }

        for(int i=1; i<=m; i++)
        {
            int u,v,p,cost,time;
            scanf("%d%d%d%d%d",&u,&v,&p,&cost,&time);
            if(e[u][v]>cost)
            {
                if(p==0)
                    e[u][v]=e[v][u]=cost;
                else
                    e[u][v]=cost;
            }
            if(e2[u][v]>time)
            {
                if(p==0)
                    e2[u][v]=e2[v][u]=time;
                else
                    e2[u][v]=time;
            }
        }
        scanf("%d%d",&S,&D);
        dijiesi2(S,D);

        //printf("Time = %d: ",d[D]);
        int tt=d[D];
        int sum=0,sum2=0;
        int ans=D,ans2=D,DD=D;
        while(path[D]!=-1)
        {
            //cout<<path[D]<<endl;
            v[sum++]=path[D];
            D=path[D];
        }
        //for(int i=sum-1;i>=0;i--)
        //printf("%d => ",v[i]);
        dijiesi1(S,DD);
        int dd=d[DD];
        while(path[DD]!=-1)
        {
            //cout<<path[D]<<endl;
            v2[sum2++]=path[DD];
            DD=path[DD];
        }
        //printf("%d\n",ans);
//        for(int i=sum-1;i>=0;i--)
//            cout<<v[i]<<" ";
//        cout<<endl;
//        for(int i=sum2-1;i>=0;i--)
//            cout<<v2[i]<<" ";
//        cout<<endl;
        int flag=1;
//        cout<<sum<<" "<<sum2<<endl;
        if(sum2==sum)
        {
            for(int i=sum-1; i>=0; i--)
                if(v[i]!=v2[i])
                {
                    flag=0;
                    break;
                }
        }
        else
            flag=0;
        if(flag)
        {
            printf("Time = %d; Distance = %d: ",tt,dd);
            for(int i=sum-1; i>=0; i--)
                printf("%d => ",v[i]);
            printf("%d\n",ans);
        }
        else
        {
            printf("Time = %d: ",tt);
            for(int i=sum-1; i>=0; i--)
                printf("%d => ",v[i]);
            printf("%d\n",ans);
            printf("Distance = %d: ",dd);
            for(int i=sum2-1; i>=0; i--)
                printf("%d => ",v2[i]);
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值