传送门
很容易想到分成 m m m层图
使用分层图暴力连边
那么就需要枚举两条地铁线和点连边,建图复杂度为 O ( n m 2 ) O(nm^2) O(nm2)
这样复杂度显然 T T T上天
考虑多建一排虚点
对应的虚电向对应的地铁线点连费用 0 0 0的边
地铁线点向对应的虚电连费用换乘的边
建图复杂度 O ( n m ) O(nm) O(nm),可以通过
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e7+10;
const int N = 1009;
const int inf = 1e9;
struct edge{
int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w)
{
d[++cnt] = (edge){v,head[u],w},head[u] = cnt;
}
typedef pair<int,int>p;
int vis[maxn],dis[maxn],ok[509][1009],maxv,n,m,s,t;
int a[N],b[N],c[N];
void dijstra(int s)
{
for(int i=0;i<=maxv;i++) dis[i] = inf,vis[i] = 0;
priority_queue<p,vector<p>,greater<p> >q;
q.push( p(0,s) ); dis[s] = 0;
while( !q.empty() )
{
int u = q.top().second; q.pop();
if( vis[u] ) continue;
vis[u] = 1;
for(int i=head[u];i;i=d[i].nxt )
{
int v = d[i].to;
if( dis[v]>dis[u]+d[i].w )
{
dis[v] = dis[u]+d[i].w;
if( !vis[v] ) q.push( p(dis[v],v) );
}
}
}
}
int main()
{
cin >> n >> m >> s >> t;
maxv = (m+1)*n;
for(int i=1;i<=m;i++)
{
cin >> a[i] >> b[i] >> c[i];
int base = (i-1)*n,last;
cin >> last; ok[i][last] = 1;
add( last+base,n*m+last,0); add(n*m+last,last+base,a[i] );
for(int j=2;j<=c[i];j++)
{
int x; cin >> x; ok[i][x] = 1;
add( last+base,x+base,b[i] ); add( x+base,last+base,b[i] );
add( x+base,n*m+x,0); add(n*m+x,x+base,a[i] );
last = x;
}
}
for(int i=1;i<=m+1;i++) add(0,(i-1)*n+s,a[i] );
dijstra(n*m+s);
int ans = 1e9;
for(int i=1;i<=m+1;i++)
ans = min( ans,dis[(i-1)*n+t] );
if( ans==1e9 ) ans = -1;
cout << ans;
}