修改边权重的Dijkstra算法最小成本
在这个问题中,我们需要使用Dijkstra算法找到从1到N的最小路径,并且我们可以将任何一条边的权重更新为cost/2。
在这里,我们将找到每个节点从源节点到目标节点的距离。之后,我们将取从源节点到节点u的最短距离和从目标节点到节点v的最短距离,并将它们与u->v边的权重的一半相加。通过这种方式,我们将找到从1到N的最小路径成本。
问题陈述 - 我们得到了一个以元组形式表示的无向图。元组{p, q, r}表示p和q之间权重为r的边。我们需要使用Dijkstra算法找到从1到N的最小路径成本。还给定我们可以执行一次操作,将任何一条边的权重更新为cost/2。
示例
输入
[{1, {2, 7}}, {1, {3, 4}}, {1, {4, 8}}, {3, {4, 4}}, {4, {5, 3}}]
输出
7
解释 - 这是给定的图。
1 / | \ 2 3 - 4 - 5
在这里,我们需要从1到达5。所以存在两条路径。一条是1->3->4->5,另一条是1->4->5。两条路径的成本都是11。如果我们选择第二条路径并将1->4的成本从8减少到4,则路径成本为7。
输入
[{1, {2, 3}}, {2, {1, 6}}, {2, {3, 2}}]
输出
3
解释 - 我们在1到2之间有两条边。因此,我们可以考虑权重为3的边,将其值更新为3/2,等于1。因此,从1到3的路径成本只有3。
方法
在这种方法中,我们将使用Dijkstra算法找到每个节点从源节点和目标节点的距离。之后,对于连接两个顶点的每条边,我们将取起始节点到源节点的距离、权重的一半和结束节点到目标节点的距离,并将它们相加。同时,我们将跟踪从1到N的最小路径成本。
算法
步骤1 - 定义一个列表来存储图。
步骤2 - 遍历每个给定的边,并执行以下步骤。
步骤2.1 - 从当前元组中获取源节点、目标节点和权重。
步骤2.2 - 在列表的源节点索引处插入{目标节点,权重}对,并在列表的目标节点索引处插入{源节点,权重}对。
步骤3 - 此外,定义source_dist和dest_dist列表分别存储每个节点到源节点和目标节点的距离。
步骤4 - 调用executeDijkstra()函数两次,分别查找每个节点到起始节点和结束节点的距离。
步骤4.1 - 在executeDijkstra()函数中,根据节点总数调整'dist'列表的大小,并将dist[source]更新为0。
步骤4.2 - 定义优先队列,并使用greater<pair<int, int>>比较器函数来使用最小堆优先队列。优先队列将用于存储当前节点到源节点的距离和节点值。
步骤4.3 - 将源节点插入队列。
步骤4.4 - 遍历队列,直到队列为空。在循环中,从队列中获取第一个元素并遍历其边。
步骤4.5 - 遍历边时,获取边的终点节点和权重。
步骤4.6 - 如果到起始节点的距离 + 边的权重小于到结束节点的距离,则更新结束节点的距离。同时,将更新后的对插入队列。
步骤5 - 定义'minCost'变量并将其初始化为从1到N的距离。
步骤6 - 开始遍历所有边。将起始节点到源节点的距离、权重的一半和结束节点到目标节点的距离相加。如果结果值大于minCost,则更新它。
步骤7 - 返回minCost值。
示例
#include <bits/stdc++.h> using namespace std; #define INF 1e9 void executeDijkstra(int source, int nodes, vector<pair<int, int>> list[], vector<int> &dist) { // Resizing dist.resize(nodes, INF); // Initialize source node with 0. dist[source] = 0; // To store edges cost priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> p_que; // Insert distance and source node p_que.push({dist[source], source}); while (!p_que.empty()) { // Get the first node from the queue int start = p_que.top().second; // Pop the top node p_que.pop(); // Traverse all connected nodes to the current node for (auto &ed : list[start]) { // Get the start and end node of the edge int end = ed.first; int cost = ed.second; // Updating the distance to minimum if (dist[start] + cost < dist[end]) { dist[end] = dist[start] + cost; p_que.push({dist[end], end}); } } } } void getMinimumCost(vector<pair<int, pair<int, int>>> &edges, int nodes, int totalEdges) { vector<pair<int, int>> list[100005]; // Traverse edges for (int p = 0; p < totalEdges; p++) { // Add graph parameters to list int source = edges[p].first; int destination = edges[p].second.first; int cost = edges[p].second.second; list[source].push_back({destination, cost}); list[destination].push_back({source, cost}); } // To store the distance of 1 to P and N to P vector<int> source_dist; vector<int> dest_dist; // For each vertex, find the path cost from the source node executeDijkstra(1, nodes + 1, list, source_dist); // For each vertex, find the path cost from the destination node executeDijkstra(nodes, nodes + 1, list, dest_dist); // To store minimum path cost int minCost = source_dist[nodes]; for (auto &ed : edges) { // Get the edges int source = ed.first; int destination = ed.second.first; int cost = ed.second.second; // Cost for 1 to N = (1 to P) + (p to p + 1) + (P + 1 to N) int cur_cost = source_dist[source] + cost / 2 + dest_dist[destination]; minCost = min(minCost, cur_cost); } cout << "The minimum cost for 1 to N after modifying any single edge is " << minCost << '\n'; } int main() { int nodes = 5; int totalEdges = 5; vector<pair<int, pair<int, int>>> edges; edges.push_back({1, {2, 7}}); edges.push_back({1, {3, 4}}); edges.push_back({1, {4, 8}}); edges.push_back({3, {4, 4}}); edges.push_back({4, {5, 3}}); getMinimumCost(edges, nodes, totalEdges); return 0; }
输出
The minimum cost for 1 to N after modifying any single edge is 7
时间复杂度 - O(MlogN)
空间复杂度 - O(N)
在这里,我们只用cost/2替换了一条边的权重。但是,程序员可以尝试编写代码来替换K条边的权重以进行更多练习。