思路:首先这道题目是一个一看就是要用分层图来做,层与层之间只有隧道将不同的层联系在一起,结合题意每次穿越隧道的转线的时候,还要等$w_i$分钟等下一班地铁的到来,这里我们选择每一站选择设置两个状态,一个是上车状态,一个是等车状态。然后对每个询问直接跑spfa。
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 1e4, M = N * 2;
int h[N], e[M], ne[M], w[M], idx, q[N], value[N], s_x, s_y, e_x, e_y, dist[N];
bool vis[N];
void add (int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}
void spfa ()
{
memset (dist, 0x3f, sizeof dist);
int hh = 0, tt = 0;
q[tt ++] = s_x * 2000 + (s_y - 1) * 2;
dist[s_x * 2000 + (s_y - 1) * 2] = 0;
while (hh != tt)
{
int t = q[hh ++];
if (hh == N) hh = 0;
vis[t] = false;
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!vis[j]) vis[j] = true, q[tt ++] = j;
if (tt == N) tt = 0;
}
}
}
}
int main()
{
int T; scanf ("%d", &T);
for (int Case = 1; Case <= T; Case ++)
{
memset (h, -1, sizeof h);
idx = 0;
int n; scanf ("%d", &n); // 线路数量。
for (int i = 1; i <= n; i ++)
{
int a; scanf ("%d%d", &a, value + i);
add (i * 2000, i * 2000 + 1, value[i]);
for (int j = 1, k = 3; j <= a - 1; j ++, k += 2) // 加一是上车状态。
{
int times; scanf ("%d", ×);
add (i * 2000 + k - 1, i * 2000 + k, value[i]);
add (i * 2000 + k - 2, i * 2000 + k, times);
add (i * 2000 + k, i * 2000 + k - 2, times);
}
}
int m, cnt = 1; scanf ("%d", &m);
for (int i = 1; i <= m; i ++, cnt ++)
{
int a, b, c, d, e; scanf ("%d%d%d%d%d", &a, &b, &c, &d, &e);
add (a * 2000 + (b - 1) * 2 + 1, c * 2000 + (d - 1) * 2, e);
add (a * 2000 + (b - 1) * 2, c * 2000 + 2 * (d - 1), e);
add (c * 2000 + (d - 1) * 2, a * 2000 + (b - 1) * 2, e);
add (c * 2000 + (d - 1) * 2 + 1, a * 2000 + (b - 1) * 2, e);
}
int Q; scanf ("%d", &Q);
printf ("Case #%d:\n", Case);
while (Q --)
{
scanf ("%d%d%d%d", &s_x, &s_y, &e_x, &e_y);
spfa();
int t = min(dist[e_x * 2000 + (e_y - 1) * 2], dist[e_x * 2000 + (e_y - 1) * 2 + 1]);
if (t != 0x3f3f3f3f)printf ("%d\n", t);
else puts ("-1");
}
}
return 0;
}