牛客网16445题:Dijkstra算法解决共享单车问题
一、题目解读
本题属于加权无向图中的最短路径变形问题,核心在于处理"步行"和"骑行"两种移动状态的切换。题目特色在于:
二、解题思路分析
本解法采用改进的Dijkstra算法,关键点包括:
三、详细解题步骤
四、完整代码实现
#include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; typedef long long ll; typedef pair<ll, int> pli; const int MAXN = 1e5 + 5; const ll INF = LLONG_MAX; vector<pair<int, int>> adj[MAXN]; bool has_bike[MAXN] = {false}; struct State { ll dist; int node; bool has_bike; bool operator>(const State& other) const { return dist > other.dist; } }; //Dijkstra算法 void dijkstra(int start, int n, vector<ll>& dist) { priority_queue<State, vector<State>, greater<State>> pq; dist.assign(2 * n + 2, INF); // 初始状态:步行到达起点 dist[start] = 0; pq.push({0, start, has_bike[start]}); while (!pq.empty()) { State current = pq.top(); pq.pop(); ll current_dist = current.dist; int u = current.node; bool bike = current.has_bike; if (current_dist > dist[u + (bike ? n : 0)]) continue; for (auto &edge : adj[u]) { int v = edge.first; int w = edge.second; // 步行状态 if (!bike) { ll new_dist = current_dist + w; if (new_dist < dist[v]) { dist[v] = new_dist; pq.push({new_dist, v, has_bike[v]}); } } // 骑车状态(包括新获得自行车的情况) bool new_bike = bike || has_bike[u]; ll bike_dist = current_dist + (new_bike ? w / 2 : w); int bike_state = v + (new_bike ? n : 0); if (bike_dist < dist[bike_state]) { dist[bike_state] = bike_dist; pq.push({bike_dist, v, new_bike}); } } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m; cin >> n >> m; for (int i = 0; i < m; ++i) { int u, v, w; cin >> u >> v >> w; adj[u].emplace_back(v, w); adj[v].emplace_back(u, w); } int k; cin >> k; for (int i = 0; i < k; ++i) { int node; cin >> node; has_bike[node] = true; } vector<ll> dist(2 * n + 2, INF); dijkstra(1, n, dist); ll result = min(dist[n], dist[2 * n]); if (result == INF) { cout << -1 << endl; } else { cout << result << endl; } return 0; }
五、算法总结
本题解通过状态机思想扩展传统Dijkstra算法,完美处理了移动方式切换带来的复杂度。该解法具有:
时间复杂度:O(MlogN) (与标准Dijkstra同阶)
空间复杂度:O(N+M)
适用场景:所有边权非负的加权图
可扩展性:可适配其他状态依赖型最短路径问题
原创内容 转载请注明出处