很有挑战的一题 直接暴力建图的话毫无疑问O(n^2)会TLE 每层虚拟一个点又会让没有点的层也能连过去
参考kuangbin菊苣的方法每层用了两个虚拟点 n+i*2-1 是入口 n+i*2 是出口 然后建单向边就可以了
VA了一次 因为MAXN应该比数据量大两倍 不小心忽略了 至于MAXM直接开到了1e7
#include <iostream> #include <string> #include <cstdio> #include <cmath> #include <cstring> #include <queue> #include <map> #include <vector> #include <set> #include <algorithm> #define INF 0x3F3F3F3F using namespace std; const int MAXN = 1e6 + 10; const int MAXM = 2e7 + 10; typedef pair<int, int> pii; struct cmp{ bool operator ()(const pii a, const pii b){ return a.first > b.first; } }; int size, head[MAXN], point[MAXM], nxt[MAXM], val[MAXM]; int t, n, m, c, dist[MAXN]; void init() { size = 0; memset(head, -1, sizeof head); } inline void add(int from, int to, int value) { val[size] = value; point[size] = to; nxt[size] = head[from]; head[from] = size++; } void dij(){ priority_queue<pii, vector<pii>, cmp> q; memset(dist, 0x3f, sizeof dist); q.push(make_pair(0, 1)); dist[1] = 0; while(!q.empty()){ pii u = q.top(); q.pop(); if(u.first > dist[u.second]) continue; for(int i = head[u.second]; ~i; i = nxt[i]){ if(dist[point[i]] > dist[u.second] + val[i]){ dist[point[i]] = dist[u.second] + val[i]; q.push(make_pair(dist[point[i]], point[i])); } } } } int main() { scanf("%d", &t); for(int kase = 1; kase <= t; kase++){ init(); scanf("%d%d%d", &n, &m, &c); for(int i = 1; i <= n; i++){ int layer; scanf("%d", &layer); add(n + 2*layer - 1, i, 0); add(i, n + 2*layer, 0); } for(int i = 1; i < n; i++){ add(n + 2*i, n + 2*(i+1) - 1, c); add(n + 2*(i+1), n + 2*i - 1, c); } int u, v, w; for(int i = 1; i <= m; i++){ scanf("%d%d%d", &u, &v, &w); add(u, v, w); add(v, u, w); } dij(); printf("Case #%d: %d ", kase, dist[n] == INF ? -1 : dist[n]); } return 0; }