首先在逻辑上将所有顶点划为 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;
}

京公网安备 11010502036488号