首先在逻辑上将所有顶点划为 2 个阵营,使用 Dijkstra 算法分别计算 2 个阵营内部的最短路径,其中,阵营 1 以顶点 1 为源点,阵营 2 以顶点 2 为源点。
然后遍历所有“跨域边”,找到该边连接的两点分别离顶点 1 和顶点 2 的最短路径,再加上这条边的长度,就是 M 先生回家要走的路程。最后取最小的路程作为答案输出。(代码附在最后)
代码(很容易读懂):
时间消耗:6ms(击败 95.07% 用户)
内存消耗:672KB(击败 96.41% 用户)
#include <iostream> #include <cstdio> #include <vector> #include <queue> #include <cstring> #include <climits> #include <algorithm> using namespace std; const int MAXN = 1005; const int INF = INT_MAX; struct Edge { int to; // 边指向的顶点id int length; // 边的长度 Edge(int to, int length) : to(to), length(length) {} }; struct Point { int id; // 顶点编号 int distance; // 从源点s到该点的路径距离 Point(int id, int distance) : id(id), distance(distance) {} bool operator< (Point p) const { return distance > p.distance; } }; vector<Edge> graph[MAXN]; // 邻接表实现的图 int dis[3][MAXN]; // 源点s到各点的距离(分为阵营1和阵营2,索引0那一行不用) int leader[MAXN]; // 表示各点的领导者,取值为1或2 void dijkstra(int s) { int ld = leader[s]; priority_queue<Point> q; dis[ld][s] = 0; q.push(Point(s, dis[ld][s])); while (!q.empty()) { int u = q.top().id; q.pop(); for (int i = 0; i < graph[u].size(); i++) { int v = graph[u][i].to; if (leader[v] != ld) { continue; } int len = graph[u][i].length; if (dis[ld][v] > dis[ld][u] + len) { // 新的路径在距离上优于之前的路径,则更新 dis[ld][v] = dis[ld][u] + len; q.push(Point(v, dis[ld][v])); } } } } int main() { int n; while (scanf("%d", &n) != EOF) { if (n == 0) { break; } int m; scanf("%d", &m); memset(graph, 0, sizeof(graph)); fill(dis[1], dis[1] + n + 1, INF); fill(dis[2], dis[2] + n + 1, INF); while (m--) { int from, to, length; scanf("%d%d%d", &from, &to, &length); graph[from].push_back(Edge(to, length)); graph[to].push_back(Edge(from, length)); } for (int i = 1; i <= n; i++) { int ld; scanf("%d", &ld); leader[i] = ld; } dijkstra(1); dijkstra(2); // 遍历所有连接两个不同阵营的道路 int ans = INF; for (int i = 1; i <= n; i++) { for (auto& edge : graph[i]) { int j = edge.to; int ld_i = leader[i], ld_j = leader[j]; if (ld_i != ld_j) { // 如果这条道路是连接两个不同阵营的 int dis_i = dis[ld_i][i], dis_j = dis[ld_j][j]; if (dis_i != INF && dis_j != INF) { ans = min(ans, dis_i + dis_j + edge.length); } } } } if (ans == INF) { printf("-1\n"); } else { printf("%d\n", ans); } } return 0; }