原題描述易誤解。正確理解:給定無向圖,每個節點 i 有權重 W[i],邊權為 w。求 每個節點到節點 1 的最短路徑距離 dis[i] × W[i] 的總和。若有節點無法到達 1,輸出 No Answer。
圖中邊權非負,可用 Dijkstra,但 SPFA 寫法簡短、對負權邊也有韌性(本題無負權),且 n ≤ 50000, m ≤ 50000 時表現優異。
add(u,v,w); add(v,u,w);long long (__int64)。INF = 1e18。inque[] 標記是否在隊列中,避免重複入隊。#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 4e18;
const int MAXN = 50010;
const int MAXM = 50010;
struct Edge { int to; ll w; int next; };
Edge edges[2*MAXM];
int head[MAXN], ecnt;
ll W[MAXN], dis[MAXN];
bool inq[MAXN];
int n, m;
void init() {
fill(head, head+n+1, -1);
ecnt = 0;
}
void addEdge(int u, int v, ll w) {
edges[ecnt] = {v, w, head[u]};
head[u] = ecnt++;
}
void spfa() {
queue q;
fill(dis, dis+n+1, INF);
fill(inq, inq+n+1, false);
dis[1] = 0;
q.push(1);
inq[1] = true;
while (!q.empty()) {
int u = q.front(); q.pop();
inq[u] = false;
for (int e = head[u]; e != -1; e = edges[e].next) {
int v = edges[e].to;
ll w = edges[e].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int T; cin >> T;
while (T--) {
cin >> n >> m;
init();
for (int i = 1; i <= n; ++i) cin >> W[i];
for (int i = 0; i < m; ++i) {
int u, v; ll w; cin >> u >> v >> w;
addEdge(u, v, w);
addEdge(v, u, w);
}
spfa();
ll ans = 0;
bool ok = true;
for (int i = 2; i <= n; ++i) {
if (dis[i] == INF) { ok = false; break; }
ans += dis[i] * W[i];
}
if (ok) cout << ans << '\n';
else cout << "No Answer\n";
}
return 0;
}
O(k·m),k 為平均鬆弛輪數,通常很小。O(n·m),但隨機圖/無負環圖極快。O(n + m)。dis[i] * W[i] 可能超過 32 位,必須用 64 位整數。head、dis、inq、ecnt。No Answer 大小寫與空格完全一致。Dijkstra + 優先隊列同樣可行(O(m log n)),但 SPFA 代碼更短、無需 priority_queue、對稠密圖常數更小。本題邊數較多(5萬),SPFA 實測更快。
POJ 3031 核心是單源最短路徑(SPFA/Dijkstra)+ 加權求和。關鍵在於正確理解題意、使用 64 位整數防溢位、無向圖建雙向邊。SPFA 實作簡潔高效,是此類題目的首選模板。