解题思路
这是一个最短路径问题,但有以下特殊条件:
- 图中某些节点有共享单车
- 如果骑单车,边的权重会变为原来的一半
- 一旦获得单车就可以一直使用
- 需要从节点1到达节点
,如果不可达则输出-1
解决方案:
- 使用Dijkstra算法的变体
- 状态需要记录:(节点编号, 是否有单车)
- 使用优先队列优化
- 对每个节点维护两种状态的最短距离:有车到达的最短距离和无车到达的最短距离
代码
#include <bits/stdc++.h>
using namespace std;
struct Node {
long val; // 当前路径长度
int index; // 当前节点编号
bool has_bike; // 是否有单车
};
class CompareNode {
public:
bool operator()(const Node& lhs, const Node& rhs) const {
return lhs.val > rhs.val;
}
};
int main() {
int n, m;
scanf("%d %d", &n, &m);
// 建图
vector<vector<pair<int,int>>> graph(n+1);
for(int i = 0; i < m; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
graph[u].push_back({v, w});
graph[v].push_back({u, w});
}
// 记录有单车的节点
vector<bool> has_bike(n+1, false);
int k;
scanf("%d", &k);
for(int i = 0; i < k; i++) {
int id;
scanf("%d", &id);
has_bike[id] = true;
}
// 初始化访问数组
vector<vector<long>> visit(n+1, vector<long>(2, LONG_MAX));
visit[1][has_bike[1]] = 0;
// Dijkstra算法
priority_queue<Node, vector<Node>, CompareNode> q;
q.push({0, 1, has_bike[1]});
while(!q.empty()) {
Node curr = q.top();
q.pop();
if(curr.index == n) {
printf("%ld\n", curr.val);
return 0;
}
for(auto& [next, weight] : graph[curr.index]) {
long time = curr.val + (curr.has_bike ? weight/2 : weight);
bool next_has_bike = curr.has_bike || has_bike[next];
if(time < visit[next][next_has_bike]) {
visit[next][next_has_bike] = time;
q.push({time, next, next_has_bike});
}
}
}
printf("-1\n");
return 0;
}
import java.util.*;
public class Main {
static class Node {
long val;
int index;
boolean hasBike;
Node(long val, int index, boolean hasBike) {
this.val = val;
this.index = index;
this.hasBike = hasBike;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
// 建图
List<List<int[]>> graph = new ArrayList<>(n + 1);
for(int i = 0; i <= n; i++) {
graph.add(new ArrayList<>());
}
for(int i = 0; i < m; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
int w = sc.nextInt();
graph.get(u).add(new int[]{v, w});
graph.get(v).add(new int[]{u, w});
}
// 记录有单车的节点
boolean[] hasBike = new boolean[n + 1];
int k = sc.nextInt();
for(int i = 0; i < k; i++) {
hasBike[sc.nextInt()] = true;
}
// 初始化访问数组
long[][] visit = new long[n + 1][2];
for(long[] row : visit) {
Arrays.fill(row, Long.MAX_VALUE);
}
visit[1][hasBike[1] ? 1 : 0] = 0;
// Dijkstra算法
PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> Long.compare(a.val, b.val));
pq.offer(new Node(0, 1, hasBike[1]));
while(!pq.isEmpty()) {
Node curr = pq.poll();
if(curr.index == n) {
System.out.println(curr.val);
return;
}
for(int[] next : graph.get(curr.index)) {
long time = curr.val + (curr.hasBike ? next[1]/2 : next[1]);
boolean nextHasBike = curr.hasBike || hasBike[next[0]];
if(time < visit[next[0]][nextHasBike ? 1 : 0]) {
visit[next[0]][nextHasBike ? 1 : 0] = time;
pq.offer(new Node(time, next[0], nextHasBike));
}
}
}
System.out.println(-1);
}
}
import heapq
from collections import defaultdict
def solve():
n, m = map(int, input().split())
# 建图
graph = defaultdict(list)
for _ in range(m):
u, v, w = map(int, input().split())
graph[u].append((v, w))
graph[v].append((u, w))
# 记录有单车的节点
has_bike = [False] * (n + 1)
k = int(input())
for _ in range(k):
has_bike[int(input())] = True
# 初始化访问数组
visit = [[float('inf')] * 2 for _ in range(n + 1)]
visit[1][has_bike[1]] = 0
# Dijkstra算法
pq = [(0, 1, has_bike[1])] # (距离, 节点, 是否有车)
while pq:
val, curr, curr_has_bike = heapq.heappop(pq)
if curr == n:
print(val)
return
for next_node, weight in graph[curr]:
time = val + (weight // 2 if curr_has_bike else weight)
next_has_bike = curr_has_bike or has_bike[next_node]
if time < visit[next_node][next_has_bike]:
visit[next_node][next_has_bike] = time
heapq.heappush(pq, (time, next_node, next_has_bike))
print(-1)
solve()
算法及复杂度
- 算法:Dijkstra最短路径算法的变体
- 时间复杂度:
-
是节点数,
是边数
- 空间复杂度:
- 需要存储访问数组和优先队列