最短路径(dijkstra)以及输出路径

河南理工大学算法协会暑期集训积分赛(四)

B. wzy的大冒险——出发咯QAQ
单点时限: 2.0 sec

内存限制: 512 MB

wzy踏上了冒险的旅程。
现在他从地精手里买了一份地图,地图上有n个城镇。
他从第一个城镇出发,走向(没钱只能走)第n个城镇,现在,请你帮wzy找到一条最短的路径,并倒序(从n到1)输出一条最短路径。
举个栗子:如果有两条路径6 4 3 1和6 5 2 1,我们选择6 4 3 1这条。
地精小提示:路是单向的QAQ。

输入格式
第一行两个数n,m ,(1≤n≤103,1≤m≤103)

接下来m行,每行三个数x,y,z,表示点 x 与点 y 之间有一条权值为 z 的有向边 (1≤x,y,z≤103).

输出格式
第一行一个整数表示 1 到 n 的最短距离;
第二行倒序输出这条路径。

样例
input
5 7
1 2 69
1 3 87
1 4 79
2 5 94
2 3 10
3 5 79
4 5 43
output
122
5 4 1

分析:
要求最短路径很简单,直接套用模板就可以;关键是输出路径;竞赛的时候,脑子短路了,陷入思维定式,然后卡了两个多小时不知道怎么输出路径,终于在结束前6秒AC了,真的是懵逼的…压哨…

先贴一下我的代码;


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxx=1e3+7;
const int mod=1e9+7;
#define INF 0x3f3f3f3f
//vector<pair<int,int> > G[maxx];
int dis[maxx];
int c[maxx][maxx];
int cc[maxx][maxx];
int s[maxx];
int v,n,m;
void dijkstra()
{
    for(int i=1;i<=n;i++) dis[i]=c[v][i];
    dis[v]=0;
    s[v]=1;
    for(int i=2;i<=n;i++)
    {
        int temp=INF;
        int u=v;
        for(int j=1;j<=n;j++)
        {
            if(!s[j]&&dis[j]<temp)
            {
                u=j;
                temp=dis[j];
            }
        }
        s[u]=1;
        for(int j=1;j<=n;j++)
        {
            if(!s[j]&&c[u][j]<INF)
            {
                int newdis=dis[u]+c[u][j];
                if(newdis<dis[j])
                {
                    dis[j]=newdis;
                }
            }
        }
    }

}
int main()
{
    cin >>n>>m;
    int x,y,z;
    memset(dis,INF,sizeof dis);
    memset(s,0,sizeof 0);
    memset(c,INF,sizeof c);
    memset(cc,INF,sizeof cc);
    for(int i=0;i<m;i++)
    {
        cin >>x>>y>>z;
        c[x][y]=z;
        cc[y][x]=z;//这个数组保证输出路径的时候不会往回走
    }
    v=1;
    dijkstra();
    cout <<dis[n]<<endl;
    int u;
    int e=n;
    cout <<e;//先输出最后一个点
    while(1)//现在开始输出路径;倒着输出;
    {
        for(u=1;u<=n;u++)//从所有的点中找到与上个点相连的点
        {
            if(dis[e]-dis[u]==cc[e][u]&&cc[e][u]!=INF)//如果这个点上个点相连,并且在最短路径上面那么输出这个点,并且在从这个点寻找路径上的下一个点
            {
                e=u;
                cout <<" "<<e;
                break;
            }
        }
        if(e==1)
            break;
    }
    cout <<endl;
    return 0;
}

这是我做题时想到的一个思路;后来在网上借鉴了许多大佬的通用方法;

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxx=1e3+10;
const int mod=1e9+7;
#define INF 0x3f3f3f3f
int dis[maxx];
int c[maxx][maxx];
int s[maxx];
int pt[maxx];
int v,n,m;
void dijkstra()
{
    for(int i=2;i<=n;i++) dis[i]=c[v][i];//经过此k点到达j点的路径是否小于其他到达j点的路径
    dis[v]=0;
    s[v]=1;
    for(int i=2;i<=n;i++)//共循环n-1次,每循环一次,确定一条最短路,再次循环时这条路就不用考虑了,去寻找下一条最短路
    {
        int temp=INF;
        int u=v;
        for(int j=1;j<=n;j++)//在源点找到一个离他最近的点(并且没有被标记过),并且标记该点,然后使用
        {
            if(!s[j]&&dis[j]<temp)
            {
                u=j;
                temp=dis[j];
            }
        }
        s[u]=1;
        for(int j=1;j<=n;j++)
        {
            if(!s[j]&&c[u][j]<INF)
            {
                int newdis=dis[u]+c[u][j];
                if(newdis<dis[j])//经过此k点到达j点的路径是否小于其他到达j点的路径
                {
                    dis[j]=newdis;
                    pt[j]=u;//表示最短路径j点是由u点传过来的
                }
            }
        }
    }

}
int main()
{
    cin >>n>>m;
    int x,y,z;
    memset(dis,INF,sizeof dis);
    memset(s,0,sizeof 0);
    memset(c,INF,sizeof c);
    for(int i=0;i<m;i++)
    {
        cin >>x>>y>>z;
        c[x][y]=z;//此处一定要存储成有向图,否则有些路径会发生错误;
    }
    for(int i=2;i<=n;i++)
    {
        if(c[1][i]!=INF)//把所有直接与1相连的点,上级都标记为1
            pt[i]=1;
    }
    v=1;
    dijkstra();
    cout <<dis[n]<<endl;
    int u=n;
    cout<<u;
    while(u!=1)
    {
        u=pt[u];
        cout <<" "<<u;
    }
    cout <<'\n';
    return 0;
}

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值