题意:有两种路径,每个点会分别在某一层,层相邻之间权值c.还有直接两点传送,花费w.问1到n的最短距离.
分析:1~n正常建边.然后n + a[i]表示i点在第a[i]层.然后再优化些就不会超时了.
#include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int N = 2e5 + 5; const int E = N * 20; const int INF = 0x3f3f3f3f; struct Edge { int v, w, nex; Edge() {} Edge(int v, int w, int nex) : v (v), w (w), nex (nex) {} }edge[E]; int head[N]; int d[N]; int a[N]; bool vv[N]; bool vis[N]; int n, m, e; void init(void) { memset (head, -1, sizeof (head)); memset (vv, false, sizeof (vv)); e = 0; } void add_edge(int u, int v, int w) { edge[e] = Edge (v, w, head[u]); head[u] = e++; } void SPFA(int s) { memset (vis, false, sizeof (vis)); memset (d, INF, sizeof (d)); d[s] = 0; vis[s] = true; queue<int> que; que.push (s); while (!que.empty ()) { int u = que.front (); que.pop (); vis[u] = false; for (int i=head[u]; ~i; i=edge[i].nex) { int v = edge[i].v, w = edge[i].w; if (d[v] > d[u] + w) { d[v] = d[u] + w; if (!vis[v]) { vis[v] = true; que.push (v); } } } } } int main(void) { int T, cas = 0; scanf ("%d", &T); while (T--) { init (); int c; scanf ("%d%d%d", &n, &m, &c); for (int i=1; i<=n; ++i) { scanf ("%d", &a[i]); vv[a[i]] = true; } for (int i=1; i<n; ++i) { if (vv[i] && vv[i+1]) { add_edge (n+i, n+i+1, c); add_edge (n+i+1, n+i, c); } } for (int i=1; i<=n; ++i) { add_edge (n+a[i], i, 0); if (a[i] > 1) add_edge (i, n+a[i]-1, c); if (a[i] < n) add_edge (i, n+a[i]+1, c); } for (int u, v, w, i=1; i<=m; ++i) { scanf ("%d%d%d", &u, &v, &w); add_edge (u, v, w); add_edge (v, u, w); } SPFA (1); printf ("Case #%d: %d ", ++cas, d[n] == INF ? -1 : d[n]); } return 0; }