• 2023.11.15 每日一题(AI自生成应用)【C++】【Python】【Java】【Go】 动态路径分析


    目录

    一、题目

    二、解决方法

    三、改进


    一、题目

    背景: 在一个城市中,有数个交通节点,每个节点间有双向道路相连。每条道路具有一个初始权重,代表通行该路段的成本(例如时间、费用等)。随着时间的变化,道路的权重可能会发生变化,比如由于交通堵塞或道路维修。

    问题: 设计一个算法,以处理以下两种类型的查询:

    1. 更新查询:给定两个节点及新的权重值,更新这两个节点之间道路的权重。
    2. 最短路径查询:给定两个节点,找出这两个节点之间的最短路径及其权重。

    输入格式

    输出格式

    • 对于每个最短路径查询,输出一个整数,表示最短路径的权重。如果两个节点之间没有路径,则输出 -1

    实际应用: 这个问题可以应用于交通管理系统,例如实时更新交通状况并为司机提供最优路线。也适用于网络数据流量管理,其中节点代表数据中心,道路代表连接它们的网络。

    挑战

    • 设计一个高效的数据结构来存储和更新节点间的道路权重。
    • 实现一个算法来快速回答最短路径查询,考虑到道路权重可能频繁变化。

    二、解决方法

    解决:

    为了解决这个动态路径分析问题,我们可以采用以下策略:

    1. 数据结构:使用邻接表来表示图,其中每个节点都有一个列表存储它与其他节点的连接及其权重。
    2. 路径更新:对于更新操作,我们只需要修改邻接表中对应的权重。
    3. 最短路径查询:使用 Dijkstra 算法来找到最短路径。由于权重可能会频繁变化,我们在每次查询时都从头开始执行 Dijkstra 算法。

    C++实现:

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. typedef pair<int, int> pii; // pair of (weight, node)
    7. class Graph {
    8. int V; // Number of vertices
    9. vector> adj; // Adjacency list
    10. public:
    11. Graph(int V) : V(V), adj(V) {}
    12. void addEdge(int u, int v, int w) {
    13. adj[u].push_back({w, v});
    14. adj[v].push_back({w, u}); // For undirected graph
    15. }
    16. void updateEdge(int u, int v, int w) {
    17. // Update weight for edge u-v
    18. for (auto &p : adj[u]) {
    19. if (p.second == v) {
    20. p.first = w;
    21. break;
    22. }
    23. }
    24. for (auto &p : adj[v]) {
    25. if (p.second == u) {
    26. p.first = w;
    27. break;
    28. }
    29. }
    30. }
    31. int shortestPath(int source, int destination) {
    32. priority_queue, greater> pq;
    33. vector<int> dist(V, INT_MAX);
    34. pq.push({0, source});
    35. dist[source] = 0;
    36. while (!pq.empty()) {
    37. int u = pq.top().second;
    38. pq.pop();
    39. for (auto &[w, v] : adj[u]) {
    40. if (dist[v] > dist[u] + w) {
    41. dist[v] = dist[u] + w;
    42. pq.push({dist[v], v});
    43. }
    44. }
    45. }
    46. return (dist[destination] == INT_MAX) ? -1 : dist[destination];
    47. }
    48. };
    49. int main() {
    50. int N, M, u, v, w;
    51. cin >> N >> M;
    52. Graph g(N);
    53. for (int i = 0; i < M; ++i) {
    54. cin >> u >> v >> w;
    55. g.addEdge(u, v, w);
    56. }
    57. // Queries
    58. char queryType;
    59. while (cin >> queryType) {
    60. if (queryType == 'U') {
    61. cin >> u >> v >> w;
    62. g.updateEdge(u, v, w);
    63. } else if (queryType == 'Q') {
    64. cin >> u >> v;
    65. cout << g.shortestPath(u, v) << endl;
    66. }
    67. }
    68. return 0;
    69. }

    Python:

    1. import heapq
    2. class Graph:
    3. def __init__(self, V):
    4. self.V = V
    5. self.graph = {i: {} for i in range(V)}
    6. def add_edge(self, u, v, w):
    7. self.graph[u][v] = w
    8. self.graph[v][u] = w
    9. def update_edge(self, u, v, w):
    10. if v in self.graph[u]:
    11. self.graph[u][v] = w
    12. if u in self.graph[v]:
    13. self.graph[v][u] = w
    14. def shortest_path(self, source, destination):
    15. dist = [float('inf')] * self.V
    16. dist[source] = 0
    17. pq = [(0, source)]
    18. while pq:
    19. d, u = heapq.heappop(pq)
    20. if d > dist[u]:
    21. continue
    22. for v, w in self.graph[u].items():
    23. if dist[u] + w < dist[v]:
    24. dist[v] = dist[u] + w
    25. heapq.heappush(pq, (dist[v], v))
    26. return dist[destination] if dist[destination] != float('inf') else -1
    27. # Example usage
    28. g = Graph(N) # N is the number of vertices
    29. # Add edges and handle queries similarly to the C++ example

    JAVA:

    1. import java.util.*;
    2. public class Graph {
    3. private int V;
    4. private Map> adj;
    5. public Graph(int V) {
    6. this.V = V;
    7. this.adj = new HashMap<>();
    8. for (int i = 0; i < V; i++) {
    9. adj.put(i, new HashMap<>());
    10. }
    11. }
    12. public void addEdge(int u, int v, int w) {
    13. adj.get(u).put(v, w);
    14. adj.get(v).put(u, w);
    15. }
    16. public void updateEdge(int u, int v, int w) {
    17. if (adj.get(u).containsKey(v)) {
    18. adj.get(u).put(v, w);
    19. }
    20. if (adj.get(v).containsKey(u)) {
    21. adj.get(v).put(u, w);
    22. }
    23. }
    24. public int shortestPath(int source, int destination) {
    25. int[] dist = new int[V];
    26. Arrays.fill(dist, Integer.MAX_VALUE);
    27. dist[source] = 0;
    28. PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
    29. pq.add(new int[]{source, 0});
    30. while (!pq.isEmpty()) {
    31. int[] current = pq.poll();
    32. int u = current[0];
    33. if (u == destination) {
    34. break;
    35. }
    36. for (Map.Entry entry : adj.get(u).entrySet()) {
    37. int v = entry.getKey();
    38. int weight = entry.getValue();
    39. if (dist[u] + weight < dist[v]) {
    40. dist[v] = dist[u] + weight;
    41. pq.add(new int[]{v, dist[v]});
    42. }
    43. }
    44. }
    45. return dist[destination] == Integer.MAX_VALUE ? -1 : dist[destination];
    46. }
    47. // Example usage
    48. public static void main(String[] args) {
    49. Graph g = new Graph(N); // N is the number of vertices
    50. // Add edges and handle queries similarly to the C++ example
    51. }
    52. }

    Go语言:

    1. package main
    2. import (
    3. "container/heap"
    4. "fmt"
    5. "math"
    6. )
    7. type Edge struct {
    8. node, weight int
    9. }
    10. type Graph struct {
    11. V int
    12. edges map[int]map[int]int
    13. }
    14. func NewGraph(V int) *Graph {
    15. g := &Graph{
    16. V: V,
    17. edges: make(map[int]map[int]int),
    18. }
    19. for i := 0; i < V; i++ {
    20. g.edges[i] = make(map[int]int)
    21. }
    22. return g
    23. }
    24. func (g *Graph) UpdateEdge(u, v, w int) {
    25. if _, ok := g.edges[u][v]; ok {
    26. g.edges[u][v] = w
    27. }
    28. if _, ok := g.edges[v][u]; ok {
    29. g.edges[v][u] = w
    30. }
    31. }
    32. func (g *Graph) ShortestPath(source, destination int) int {
    33. dist := make([]int, g.V)
    34. for i := range dist {
    35. dist[i] = math.MaxInt32
    36. }
    37. dist[source] = 0
    38. pq := make(PriorityQueue, 0)
    39. heap.Init(&pq)
    40. heap.Push(&pq, &Item{
    41. value: source,
    42. priority: 0,
    43. })
    44. for pq.Len() > 0 {
    45. item := heap.Pop(&pq).(*Item)
    46. u := item.value
    47. if u == destination {
    48. break
    49. }
    50. for v, w := range g.edges[u] {
    51. if dist[u]+w < dist[v] {
    52. dist[v] = dist[u] + w
    53. heap.Push(&pq, &Item{
    54. value: v,
    55. priority: dist[v],
    56. })
    57. }
    58. }
    59. }
    60. if dist[destination] == math.MaxInt32 {
    61. return -1
    62. }
    63. return dist[destination]
    64. }
    65. // Define the priority queue used for Dijkstra's algorithm
    66. type Item struct {
    67. value int // The node index
    68. priority int // The node's priority (distance)
    69. index int // The index of the item in the heap
    70. }
    71. type PriorityQueue []*Item
    72. func (pq PriorityQueue) Len() int { return len(pq) }
    73. func (pq PriorityQueue) Less(i, j int) bool {
    74. return pq[i].priority < pq[j].priority
    75. }
    76. func (pq PriorityQueue) Swap(i, j int) {
    77. pq[i], pq[j] = pq[j], pq[i]
    78. pq[i].index = i
    79. pq[j].index = j
    80. }
    81. func (pq *PriorityQueue) Push(x interface{}) {
    82. n := len(*pq)
    83. item := x.(*Item)
    84. item.index = n
    85. *pq = append(*pq, item)
    86. }
    87. func (pq *PriorityQueue) Pop() interface{} {
    88. old := *pq
    89. n := len(old)
    90. item := old[n-1]
    91. old[n-1] = nil
    92. item.index = -1
    93. *pq = old[0 : n-1]
    94. return item
    95. }
    96. func main() {
    97. // Example usage
    98. g := NewGraph(N) // N is the number of vertices
    99. // Add edges and handle queries similarly to the C++ example
    100. }

    三、改进

    1. 效率问题:每次查询最短路径时都需要从头执行 Dijkstra 算法。在频繁更新边权重的场景中,这可能导致效率低下。
    2. 数据结构选择:现有实现使用邻接表来存储图,这对于稀疏图是合适的。但对于密集图,这种表示方式可能导致内存使用不经济。

    改进:

    1. 增量更新算法:对于频繁更新的场景,可以考虑使用更高级的图算法,如“动态最短路径算法”。这类算法可以在不重新计算整个图的情况下,有效更新最短路径。
    2. 数据结构优化:针对不同类型的图(稀疏或密集),选择合适的数据结构。例如,对于密集图,可以使用邻接矩阵来代替邻接表。
    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. const int MAX_V = 1000; // 假设图中最多有1000个节点
    7. class Graph {
    8. int V; // 顶点数
    9. vectorint>> adjMatrix; // 邻接矩阵
    10. public:
    11. Graph(int V) : V(V), adjMatrix(V, vector<int>(V, INT_MAX)) {}
    12. void addEdge(int u, int v, int w) {
    13. adjMatrix[u][v] = w;
    14. adjMatrix[v][u] = w;
    15. }
    16. void updateEdge(int u, int v, int w) {
    17. adjMatrix[u][v] = w;
    18. adjMatrix[v][u] = w;
    19. }
    20. int shortestPath(int source, int destination) {
    21. vector<int> dist(V, INT_MAX);
    22. vector<bool> sptSet(V, false);
    23. dist[source] = 0;
    24. for (int count = 0; count < V - 1; count++) {
    25. int u = minDistance(dist, sptSet);
    26. sptSet[u] = true;
    27. for (int v = 0; v < V; v++) {
    28. if (!sptSet[v] && adjMatrix[u][v] != INT_MAX && dist[u] != INT_MAX &&
    29. dist[u] + adjMatrix[u][v] < dist[v]) {
    30. dist[v] = dist[u] + adjMatrix[u][v];
    31. }
    32. }
    33. }
    34. return (dist[destination] == INT_MAX) ? -1 : dist[destination];
    35. }
    36. private:
    37. int minDistance(const vector<int> &dist, const vector<bool> &sptSet) {
    38. int min = INT_MAX, min_index;
    39. for (int v = 0; v < V; v++) {
    40. if (!sptSet[v] && dist[v] <= min) {
    41. min = dist[v];
    42. min_index = v;
    43. }
    44. }
    45. return min_index;
    46. }
    47. };
    48. int main() {
    49. // 示例用法
    50. int N, M, u, v, w;
    51. cin >> N >> M;
    52. Graph g(N);
    53. for (int i = 0; i < M; ++i) {
    54. cin >> u >> v >> w;
    55. g.addEdge(u, v, w);
    56. }
    57. // 处理查询
    58. // ...
    59. }

            这个实现针对密集图进行了优化,但它不包括动态最短路径算法的实现。动态最短路径算法通常更复杂,可能需要使用更高级的数据结构和算法技巧。这种算法的实现和优化通常是图算法研究的前沿话题。

  • 相关阅读:
    Vue---8种组件传值方式总结,总有一款适合你
    大数据编程实验一:HDFS常用操作和Spark读取文件系统数据
    ATPCS:ARM-Thumb程序调用的基本规则
    【21天学习挑战赛】经典算法拓展-----时间复杂度学习
    你真的熟练运用 HTML5 了吗,这10 个酷炫的 H5 特性你会几个?
    RT-Thread 4. ENV安装
    EMC简述01
    Leetcode学习记录(1)
    PowerEdge RAID Controller (PERC) types for Dell EMC systems PERC11
    计算机网络八股文复习
  • 原文地址:https://blog.csdn.net/weixin_44120785/article/details/134432520