Day59-图论,卡码网47,94
- 参加科学大会(第六期模拟笔试)
-
题目描述:小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。小明的起点是第一个车站,终点是最后一个车站。然而,途中的各个车站之间的道路状况、交通拥堵程度以及可能的自然因素(如天气变化)等不同,这些因素都会影响每条路径的通行时间。小明希望能选择一条花费时间最少的路线,以确保他能够尽快到达目的地。
-
输入描述:第一行包含两个正整数,第一个正整数 N 表示一共有 N 个公共汽车站,第二个正整数 M 表示有 M 条公路。 接下来为 M 行,每行包括三个整数,S、E 和 V,代表了从 S 车站可以单向直达 E 车站,并且需要花费 V 单位的时间。
-
输出描述:输出一个整数,代表小明从起点到终点所花费的最小时间。
-
输入示例
-
7 9
-
1 2 1
-
1 3 4
-
2 3 2
-
2 4 5
-
3 4 2
-
4 5 3
-
2 6 4
-
5 7 4
-
6 7 9
-
输出示例
-
12
- 思路
- 堆优化细节,思路依然是 dijkstra 三部曲:
- 第一步,选源点到哪个节点近且该节点未被访问过
- 第二步,该最近节点被标记访问过
- 第三步,更新非访问节点到源点的距离(即更新minDist数组)
- 只不过之前是 通过遍历节点来遍历边,通过两层for循环来寻找距离源点最近节点。 这次直接遍历边,且通过堆来对边进行排序,达到直接选择距离源点最近节点。有了小顶堆自动对边的权值排序,只需要直接从 堆里取堆顶元素(小顶堆中,最小的权值在上面),就可以取到离源点最近的节点了
class PriorityQueue {
constructor(comparator) {
this.heap = [];
this.comparator = comparator || ((a, b) => a[1] - b[1]);
}
push(item) {
this.heap.push(item);
this.heap.sort(this.comparator);
}
pop() {
return this.heap.shift();
}
top() {
return this.heap[0];
}
empty() {
return this.heap.length === 0;
}
}
async function main() {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
for await (const line of rl) {
lines.push(line);
}
// 解析输入
const [n, m] = lines[0].split(' ').map(Number);
// 构建邻接表
const grid = new Array(n + 1).fill().map(() => []);
for (let i = 1; i <= m; i++) {
const [p1, p2, val] = lines[i].split(' ').map(Number);
grid[p1].push({ to: p2, val });
}
const start = 1; // 起点
const end = n; // 终点
// 存储从源点到每个节点的最短距离
const minDist = new Array(n + 1).fill(Number.MAX_SAFE_INTEGER);
// 记录顶点是否被访问过
const visited = new Array(n + 1).fill(false);
// 优先队列 (小顶堆)
const pq = new PriorityQueue((a, b) => a[1] - b[1]);
// 初始化队列,源点到源点的距离为0
pq.push([start, 0]);
minDist[start] = 0;
while (!pq.empty()) {
// 1. 获取当前距离起点最近的节点
const [currentNode, currentDist] = pq.pop();
if (visited[currentNode]) continue;
// 2. 标记当前节点为已访问
visited[currentNode] = true;
// 3. 更新邻接节点的最短距离
for (const edge of grid[currentNode]) {
const neighbor = edge.to;
const weight = edge.val;
if (!visited[neighbor] && minDist[currentNode] + weight < minDist[neighbor]) {
minDist[neighbor] = minDist[currentNode] + weight;
pq.push([neighbor, minDist[neighbor]]);
}
}
}
// 输出结果
if (minDist[end] === Number.MAX_SAFE_INTEGER) {
console.log(-1); // 不能到达终点
} else {
console.log(minDist[end]); // 到达终点的最短路径长度
}
}
main();
- 城市间货物运输 I
-
题目描述:某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。如果最低运输成本是一个负数,它表示在遵循最优路径的情况下,运输过程中反而能够实现盈利。城市 1 到城市 n 之间可能会出现没有路径的情况,同时保证道路网络中不存在任何负权回路。
-
输入描述:第一行包含两个正整数,第一个正整数 n 表示该国一共有 n 个城市,第二个整数 m 表示这些城市中共有 m 条道路。 接下来为 m 行,每行包括三个整数,s、t 和 v,表示 s 号城市运输货物到达 t 号城市,道路权值为 v (单向图)。
-
输出描述:如果能够从城市 1 到连通到城市 n, 请输出一个整数,表示运输成本。如果该整数是负数,则表示实现了盈利。如果从城市 1 没有路径可达城市 n,请输出 "unconnected"。
-
输入示例
-
6 7
-
5 6 -2
-
1 2 1
-
5 3 1
-
2 5 2
-
2 4 -3
-
4 6 4
-
1 3 5
-
输出示例
-
1
- 思路
- Bellman_ford算法的核心思想是 对所有边进行松弛n-1次操作(n为节点数量),从而求得目标最短路
if (minDist[B] > minDist[A] + value) minDist[B] = minDist[A] + value。使用minDist数组来表达 起点到各个节点的最短距离,例如minDist[3] = 5 表示起点到达节点3 的最小距离为5。对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离。对所有边松弛 n-1 次 就一定能得到 起点到达 终点的最短距离。
async function main() {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
for await (const line of rl) {
lines.push(line);
}
// 解析输入
const [n, m] = lines[0].split(' ').map(Number);
// 存储所有边
const edges = [];
for (let i = 1; i <= m; i++) {
const [p1, p2, val] = lines[i].split(' ').map(Number);
edges.push([p1, p2, val]);
}
const start = 1; // 起点
const end = n; // 终点
// 初始化最短距离数组
const minDist = new Array(n + 1).fill(Number.MAX_SAFE_INTEGER);
minDist[start] = 0; // 起点到自身的距离为0
// Bellman-Ford算法核心
for (let i = 1; i < n; i++) { // 最多进行n-1次松弛
let updated = false;
for (const [from, to, price] of edges) {
// 松弛操作
if (minDist[from] !== Number.MAX_SAFE_INTEGER &&
minDist[to] > minDist[from] + price) {
minDist[to] = minDist[from] + price;
updated = true;
}
}
// 如果没有更新,提前终止
if (!updated) break;
}
// 输出结果
if (minDist[end] === Number.MAX_SAFE_INTEGER) {
console.log('unconnected'); // 不能到达终点
} else {
console.log(minDist[end]); // 到达终点的最短路径
}
}
main();

浙公网安备 33010602011771号