码迷,mamicode.com
首页 > 其他好文 > 详细

cogs 2. 旅行计划 dijkstra+打印路径小技巧

时间:2019-09-04 00:18:42      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:math   直接   别人   mem   get   重点   def   selected   准备   

2. 旅行计划

★★   输入文件:djs.in   输出文件:djs.out   简单对比
时间限制:3 s   内存限制:128 MB

【题目描述】

过暑假了,阿杜准备出行旅游,他已经查到了某些城市的两两之间的距离及可行路线(可行路线有方向),如下图所示。请你编程计算从阿杜所住城市到其它城市的最短路径以帮助阿杜制定旅行计划。

技术图片

【输入格式】

输入由若干行组成,第一行有三个整数 n(1n100) 为城市数,m(1mn2) 为城市间道路数,s(0sn1) 是阿杜所住城市。第 2 至 m+1 行是每条路的信息,每行三个整数,为道路的起点、终点和两城市间距离。(城市从 0 开始编号)

【输出格式】

输出 n 组(按城市编号由小至大),每组三行

第一行:城市编号及一个冒号

第二行:path及一个冒号,后面是最短路径节点编号序列(编号间用一个空格隔开)

第三行:cost及一个冒号,后面是一个整数,表示路径距离

如果没有通路则输出 no

【输入样例】

6 8 0
0 2 10
0 4 30
0 5 100
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60

【输出样例】

0:
no
1:
no
2:
path:0 2
cost:10
3:
path:0 4 3
cost:50
4:
path:0 4
cost:30
5:
path:0 4 3 5
cost:60
 

 
   

看到评论区的一群大佬的评论 我立刻不淡定了  决定来瞅瞅(探头探脑   这一道据说很坑的题 没想到想了3分钟 敲了4分钟 完美AC!

 

那么这一道题到底应该咋做

我的时间复杂度是(mlogm  +  n^2)n<100  m<10000  这个时间复杂度看起来还是 很棒的

 

首先很简单 我们要来按照题目中给出的单向边和起点 跑一遍dijkstra  这是O(n)的

然后重点在于怎样输出路径

 

在之前的时候总是看到别人的代码里有一个非常神奇的数组是path  然而我并没有学过这么难的东西(俺可是初学者--哈哈)

首先我们最暴力的想法肯定是O(n^3)的

对于每一个点 从剩下的点里面 看一下哪一个点是他的前驱

很显然这一道题n^3也没啥问题

但是蒟蒻拒绝!

所以我们想办法压缩到O(n^2)

听起来不错

 

既然我们浪费时间主要在找前驱  那么我们只需要在dijkstra的过程中顺便用一个pathpre数组来存每一个点的前驱  后面直接跑一个递归调用一下下就好啦

具体看代码 还是非常好理解的优化(这是蒟蒻自己发明的!请求专利)

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define pa pair<int,int>
#define maxn 115
using namespace std;
int n,m,s;
int dis[maxn],vis[maxn],pathpre[maxn];
vector<int> v[maxn],w[maxn];
priority_queue< pa,vector<pa>,greater<pa> > q;
inline int read()
{
    int X=0; bool flag=1; char ch=getchar();
    while(ch<0||ch>9) {if(ch==-) flag=0; ch=getchar();}
    while(ch>=0&&ch<=9) {X=(X<<1)+(X<<3)+ch-0; ch=getchar();}
    if(flag) return X;
    return ~(X-1);
}
inline void write(int X)
{
    if(X<0) {X=~(X-1); putchar(-);}
    if(X>9) write(X/10);
    putchar(X%10+0);
}
void Dijkstra()
{
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty()){
        int rt=q.top().second;
        q.pop();
        if(vis[rt]) continue;
        vis[rt]=1;
        for(int i=0;i<v[rt].size();i++){
            int to=v[rt][i];
            if(dis[to]>dis[rt]+w[rt][i]){
                dis[to]=dis[rt]+w[rt][i];
                pathpre[to]=rt;
                q.push(make_pair(dis[to],to));
            }
        }
    }
}
bool flagfinish=false; 
void path_out(int rt){//最差时间复杂度:O(mlogm+n^2) 
    if(rt==s){
        write(rt);printf(" ");
        flagfinish=true;
        return;
    }
    //    for(int i=0;i<v[rt].size();i++)
        //    if(dis[v[rt][i]]==dis[rt]+w[rt][i]){   错 
    //            path_out(v[rt][i]);
    //            write(rt);printf(" ");
    //            return;
    //        }
    path_out(pathpre[rt]);write(rt);printf(" ");
}
int main()
{
    freopen("djs.in","r",stdin);
    freopen("djs.out","w",stdout);
    n=read(),m=read(),s=read();
    for(int i=1,x,y,z;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        v[x].push_back(y);w[x].push_back(z);
    }    
    Dijkstra();
    for(int i=0;i<n;i++)
    {
        write(i);puts(":");
        if(dis[i]==inf||i==s) puts("no");
        else
        {
            printf("path:");path_out(i);printf("\n");
            printf("cost:%d\n",dis[i]);flagfinish=false;
        }
    }
    return 0;
}

 

cogs 2. 旅行计划 dijkstra+打印路径小技巧

标签:math   直接   别人   mem   get   重点   def   selected   准备   

原文地址:https://www.cnblogs.com/Tidoblogs/p/11456459.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!