CSU1808:地铁-边最短路

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题目:传送门

 原题目描述及样例在最下面。

 题目大意就是n个点,m条无向边。每条边有一个权值(<=1e9)和一个标号(<=n)。求从1到n的最短路径。

 题目还有一个特殊要求,就是从一个点经过2条标号不同的边时,需额外花费边的标号差。

思路:

 又是一道边最短路,读完题发现和BZOJ4289类似。恶心的边最短路问题。

 思路与bzoj4289类似,把边当作点,跑最短路。之前按照那题的方法建图跑最短路,样例啥的都过了,但是蜜汁wa。就从网上学到了另一种方法。

边最短路:

dis[i]表示从起点 1 到编号为 i 的这条边所指向点的最短路径
维护 ans=min(dis[x]) ,边x所指向的点为n

1.首先用链式前向星建好无向图。
2.然后遍历起点1 连出去的边。初始化dis[i] = cw[i].w( i 是边的编号),并加入队列。
3.然后跑优先队列优化的dijkstra就行了。


 (不知道为什么在push的时候加vis标记就不对,如果有那位大佬是在push处加vis标记过的,求教)

AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<LL, int> pii;
const int N = 2e5+5;
const LL INF=0x3f3f3f3f3f3f3f3f;
int n,m,tot;
int vis[N],head[N];
LL dis[N];
struct lp{
    int u,v,id,nex;
    LL w;
}cw[N];
inline int ab(int x){
    return x<0?-x:x;
}
void dij(){
    priority_queue<pii,vector<pii>,greater<pii> >Q;
    for(int i=0,a,b,c,d;i<m;++i){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        cw[++tot].u=a;cw[tot].v=b;cw[tot].w=d*1LL;cw[tot].id=c;cw[tot].nex=head[a];head[a]=tot;
        cw[++tot].u=b;cw[tot].v=a;cw[tot].w=d*1LL;cw[tot].id=c;cw[tot].nex=head[b];head[b]=tot;
    }
    for(int i=head[1];~i;i=cw[i].nex){
        dis[i]=cw[i].w;
        Q.push(make_pair(dis[i],i));
    }
    LL ans=INF;
    while(!Q.empty()){
        pii now=Q.top();Q.pop();
        if(vis[now.se])continue;
        vis[now.se]=1;
        int a=cw[now.se].v,u=now.se;
        if(a==n){
            ans=min(ans,dis[u]);
        }
        for(int i=head[a];~i;i=cw[i].nex){
            if(vis[i])continue;
            if(dis[i]>dis[u]+ab(cw[i].id-cw[u].id)+cw[i].w){
                dis[i]=dis[u]+ab(cw[i].id-cw[u].id)+cw[i].w;
                Q.push(make_pair(dis[i],i));
            }
        }
    }
    printf("%lld\n",ans );
}
inline void init(){
    tot=-1;
    memset(head,-1,sizeof(head));
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
}
int main(int argc, char const *argv[]){
    while(~scanf("%d%d",&n,&m)){
        init();
        dij();
    }   
    return 0;
}


题目描述:

Description
Bobo 居住在大城市 ICPCCamp。

ICPCCamp 有 n 个地铁站,用 1,2,…,n 编号。 m 段双向的地铁线路连接 n 个地铁站,其中第 i 段地铁属于 ci 号线,位于站 ai,bi 之间,往返均需要花费 ti 分钟(即从 ai 到 bi 需要 ti 分钟,从 bi 到 ai 也需要 ti 分钟)。
众所周知,换乘线路很麻烦。如果乘坐第 i 段地铁来到地铁站 s,又乘坐第 j 段地铁离开地铁站 s,那么需要额外花费 |ci-cj | 分钟。注意,换乘只能在地铁站内进行。
Bobo 想知道从地铁站 1 到地铁站 n 所需要花费的最小时间。
Input
输入包含不超过 20 组数据。
每组数据的第一行包含两个整数 n,m (2≤n≤105,1≤m≤105).
接下来 m 行的第 i 行包含四个整数 ai,bi,ci,ti (1≤ai,bi,ci≤n,1≤ti≤109).
保证存在从地铁站 1 到 n 的地铁线路(不一定直达)。
Output
对于每组数据,输出一个整数表示要求的值。
Sample Input
3 3
1 2 1 1
2 3 2 1
1 3 1 1
3 3
1 2 1 1
2 3 2 1
1 3 1 10
3 2
1 2 1 1
2 3 1 1
Sample Output
1
3
2
Hint
Source
湖南省第十二届大学生计算机程序设计竞赛

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值