题目描述
小雨所在的城市一共有 mmm 条地铁线,分别标号为 1 号线,2 号线,……,m 号线。整个城市一共有 nnn 个车站,编号为 1∼n1 \sim n1∼n 。其中坐 i 号线需要花费 aia_iai 的价格,每坐一站就需要多花费 bib_ibi 的价格。i 号线有 cic_ici 个车站,而且这 cic_ici 个车站都已知,如果某一站有多条地铁线经过,则可以在这一站换乘到另一条地铁线,并且能多次换乘。现在小雨想从第 sss 个车站坐地铁到第 ttt 个车站,地铁等待时间忽略不计,求最少花费的价格,若不能到达输出 -1 。(地铁是双向的,所以 sss 可能大于 ttt)
输入描述:
第一行输入四个正整数 n,m,s,tn,m,s,tn,m,s,t,分别表示车站个数,地铁线数,起点站和终点站。
第二行到第 m+1m + 1m+1 行,每行前三个数为 ai,bi,cia_i,b_i,c_iai,bi,ci,分别表示坐 i 号线的价格,i 号线每坐一站多花的价格,i 号线车站个数。接下来 cic_ici 个数,表示 i 号线的每一个车站的编号,单调递增。
输出描述:
共一行,一个数表示最小花费,若不能到达输出 -1 。
题解
分层图+最短路
我们可以把每一条地铁线看作一层,对于层与层之间我们建立虚点,把不同的层之间联系起来,然后再跑最短路就OK了
那我们怎么进行分层建图呢?对于第i条线路的边,我们对其标号为i*n+x,即第一层的边是从n到2n,第二层的边是从2n到3n...以此类推。我们把所有虚点建到1到n之间,如下图:
所以我们只需要把图建好然后跑最短路就好啦。
代码
#include<bits/stdc++.h> using namespace std; #define pb push_back #define pii pair<int,int> #define fi first #define se second #define MP make_pair #define rep(i,n) for(register int i=0;i<(n);++i) #define repi(i,a,b) for(register int i=int(a);i<=(b);++i) #define repr(i,b,a) for(register int i=int(b);i>=(a);--i) template<typename T> inline T read(){ T s=0,f=1; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') f=-1;ch = getchar();} while(isdigit(ch)) {s=(s<<3)+(s<<1)+ch-48;ch = getchar();} return s*f; } #define gn() read<int>() #define gl() read<ll>() template<typename T> inline void print(T x) { if(x<0) putchar('-'), x=-x; if(x>9) print(x/10); putchar(x%10+'0'); } //////////////////////////////////////////////////////////////////////// const int N=1e6+100; int n,m,S,T; int dis[N]; int head[N]; struct node{ int to,net,w; }s[N*3]; int tot=0; void add(int u,int v,int w){ s[++tot]={v,head[u],w}; head[u]=tot; } void dij(){ priority_queue<pii > Q; Q.push({0,S}); dis[S]=0; while(!Q.empty()){ pii now=Q.top(); Q.pop(); for(int i=head[now.se];~i;i=s[i].net){ int z=s[i].to; if(dis[z]>dis[now.se]+s[i].w){ dis[z]=dis[now.se]+s[i].w; Q.push({-dis[z],z}); } } } if(dis[T]<0x3f3f3f3f)cout<<dis[T]<<'\n'; else cout<<-1<<'\n'; } //////////////////////////////////////////////////////////////////////// int main(){ n=gn(),m=gn(),S=gn(),T=gn(); for(int i=0;i<=(m+1)*n;++i){ head[i]=-1; dis[i]=0x3f3f3f3f; } repi(i,1,m){ int a=gn(),b=gn(),c=gn(); int last=-1; repi(j,1,c){ int x=gn(); if(j>1){ add(i*n+x,i*n+last,b); add(i*n+last,i*n+x,b); } add(x,i*n+x,a); add(i*n+x,x,0); last=x; } } dij(); } /** * In every life we have some trouble * When you worry you make it double * Don't worry,be happy. **/