小雨坐地铁 多层图最短路

链接

题目描述

小雨所在的城市一共有 m 条地铁线,分别标号为 1 号线,2 号线,……,m 号线。整个城市一共有 n 个车

站,编号为 1 ∼ n 1 \sim n 1n 。其中坐 i 号线需要花费 a i a_i ai 的价格,每坐一站就需要多花费 b i b_i bi 的价格。i 号

线有 c i c_i ci 个车站,而且这 c i c_i ci 个车站都已知,如果某一站有多条地铁线经过,则可以在这一站换乘到另

一条地铁线,并且能多次换乘。现在小雨想从第 s 个车站坐地铁到第 t 个车站,地铁等待时间忽略不计,

求最少花费的价格,若不能到达输出 -1 。(地铁是双向的,所以 s 可能大于 t)

输入描述:

第一行输入四个正整数 n,m,s,t,分别表示车站个数,地铁线数,起点站和终点站。

第二行到第 m + 1m+1 行,每行前三个数为 a i , b i , c i a_i,b_i,c_i ai,bi,ci ,分别表示坐 i 号线的价格,i 号线每坐一站多花

的价格,i 号线车站个数。接下来 c i c_i ci 个数,表示 i 号线的每一个车站的编号,单调递增。

输出描述:

共一行,一个数表示最小花费,若不能到达输出 -1 。
示例1

输入
5 2 1 4
2 2 3 1 3 5
2 1 4 2 3 4 5
输出
7

说明
坐 1 号线:花费 2;

1 → 3 : 1 \rightarrow 3: 13花费 2;

换乘 2 号线:花费 2;

3 → 4 3 \rightarrow 4 34:花费 1;

所以最小总花费为 7 。
备注:
1 ≤ n ≤ 1 0 3 , 1 ≤ m ≤ 500 , 1 ≤ s , t ≤ 10 1 \leq n \leq 10^3, 1 \leq m \leq 500,1 \leq s,t \leq10 1n103,1m500,1s,t10

分层图最短路,每层都是n个节点,暴力建边是 O ( n m 2 ) O(nm^2) O(nm2), 考虑现实情况,每个站都有一个大厅,所以不妨多一层图当做大厅,起点在s的大厅里,终点在t的大厅里,每层图的站点x都能直接连接x的大厅,花费为0,反之,则需要进入该条地铁线的 a i a_i ai.
代码:

#include<bits/stdc++.h>
using namespace std;
#define Init(arr,val) memset(arr,val,sizeof(arr))
const int inf=0x3f3f3f3f,mod=9999991,MAXN=1000*505,MAXE=2e6+3e3;
typedef long long ll;
struct Edge{
    int y,val,nxt;
}e[MAXE];
int cnt,head[MAXE];
inline void add(int x,int y,int val){
    e[++cnt].y=y;
    e[cnt].val=val;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
int n,m,s,t;
int dis[MAXE];
bool vis[MAXE];
struct Node{
    int y,val;
    bool operator<(const Node&other)const{return val>other.val;}
};
priority_queue<Node>heap;
void dijkstra(){
    Init(dis,inf);
    heap.push({n*n+s,0});
    dis[n*n+s]=0;
    while(!heap.empty()){
        Node tmp=heap.top();
        heap.pop();
        int now=tmp.y;
        if(vis[now])continue;
        vis[now]=1;
        for(int i=head[now];i;i=e[i].nxt){
            int to=e[i].y;
            int va=e[i].val;
            if(!vis[to]&&dis[to]>dis[now]+va){
                dis[to]=dis[now]+va;
                heap.push({to,dis[to]});
            }
        }
    }
}
int main() {
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    cin>>n>>m>>s>>t;
    for(int i=0;i<m;++i){
        int a,b,c,x,y;
        cin>>a>>b>>c>>x;
        add(i*n+x,n*n+x,0);//i*n+x 即为第i层图编号为x的站点,他能去n*n+x的大厅,花费=0
        add(n*n+x,i*n+x,a);// 
        while(--c){//--c,循环c-1次
            cin>>y;
            add(i*n+x,i*n+y,b);
            add(i*n+y,i*n+x,b);
            add(i*n+y,n*n+y,0);
            add(n*n+y,i*n+y,a);
            x=y;
        }
    }
    dijkstra();
    printf("%d",dis[n*n+t]==inf?-1:dis[n*n+t]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值