• 算法优化,最短路径。


    关注 码龄 粉丝数 原力等级 -- 被采纳 被点赞 采纳率 可乐manman 2024-04-25 19:46 采纳率: 0% 浏览 1 首页/ 数据结构与算法 / 算法优化,最短路径。 图搜索算法 问题描述 init给定图的初始化,mMap值为0表示无障碍,1表示有障碍。 add,增加的加油站station,加油可以行驶init的mRange距离。 然后求最短距离,mFrom到mTo(对应add函数的mId)。 下面是我写的算法,还能优化吗?一只超时。 import java.util.*; class UserSolution { class Node implements Comparator { int id; int x; int y; int dist; public Node() {} public Node(int id, int dist) { this.id = id; this.dist = dist; } public Node(int id, int x, int y) { this.id = id; // -1 白色, -2 灰色(障碍物) this.x = x; this.y = y; } public Node(int id, int x, int y, int dist) { this.id = id; this.x = x; this.y = y; this.dist = dist; } @Override public int compare(Node o1, Node o2) { return o1.dist - o2.dist; } } int n; int[][] graph; HashMap nodeMap = new HashMap<>(); HashMap> adjTable = new HashMap<>(); int range; int[] dx = new int[]{1, -1, 0, 0}; int[] dy = new int[]{0, 0, 1, -1}; void init(int N, int mRange, int mMap[][]) { this.n = N; this.graph = new int[n][n]; nodeMap.clear(); adjTable.clear(); this.range = mRange; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (mMap[i][j] == 0) { graph[i][j] = -1; continue; } if (mMap[i][j] == 1) { graph[i][j] = -2; } } } } void add(int mID, int mRow, int mCol) { Node insertNode = new Node(mID, mRow, mCol); nodeMap.put(mID, insertNode); graph[mRow][mCol] = mID; adjTable.put(mID, new ArrayList<>()); update(insertNode); } private void update(Node updateNode) { ArrayDeque queue = new ArrayDeque<>(); boolean[][] vis = new boolean[n][n]; queue.add(new Node(updateNode.id, updateNode.x, updateNode.y, 0)); vis[updateNode.x][updateNode.y] = true; while (!queue.isEmpty()) { Node startNode = queue.poll(); for (int i = 0; i < 4; i++) { int newX = startNode.x + dx[i]; int newY = startNode.y + dy[i]; int dist = startNode.dist + 1; if (!isOut(newX, newY)) { continue; } int id = graph[newX][newY]; if (isOut(newX, newY) && !vis[newX][newY] && id > -2 && dist <= range) { vis[newX][newY] = true; queue.add(new Node(id, newX, newY, dist)); if (id >= 0) { adjTable.get(updateNode.id).add(new Node(id, newX, newY, dist)); adjTable.get(id).add(new Node(updateNode.id, updateNode.x, updateNode.y, dist)); } } } } } private boolean isOut(int x, int y) { return x >= 0 && y >= 0 && x < n && y < n; } int distance(int mFrom, int mTo) { Node sourceNode = nodeMap.get(mFrom); Node targetNode = nodeMap.get(mTo); if (sourceNode == null || targetNode == null) { return -1; } PriorityQueue queue = new PriorityQueue<>(new Node()); boolean[] vis = new boolean[205]; vis[mFrom] = true; queue.add(new Node(sourceNode.id,0)); while (!queue.isEmpty()) { Node startNode = queue.poll(); vis[startNode.id] = true; if (startNode.id == mTo) { return startNode.dist; } for (Node node : adjTable.get(startNode.id)) { if (!vis[node.id]) { queue.add(new Node(node.id, node.dist + startNode.dist)); } } } return -1; } } 展开全部 收起 写回答 好问题 0 提建议 追加酬金 关注问题 微信扫一扫 点击复制链接 分享 邀请回答 编辑 收藏 删除 结题 收藏 举报 追加酬金 (90%的用户在追加酬金后获得了解决方案) 当前问题酬金 ¥ 0 (可追加 ¥500) ¥ 15¥ 20¥ 50¥ 100¥ 200 支付方式 扫码支付 二维码出错 点击刷新 支付金额 15 元 提供问题酬金的用户不参与问题酬金结算和分配 支付即为同意 《付费问题酬金结算规则》 结题 再想想 删除 再等等

    3条回答 默认 最新

    • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-25 19:46
      关注

      引自免费微信小程序:皆我百晓生

      在您提供的代码中,已经实现了一个基本的广度优先搜索(BFS)算法来解决从一个节点到另一个节点的最短路径问题。然而,这个实现有一些可以优化的地方。以下是针对您的代码进行的一些优化建议:

      1. 合并更新与搜索:将update方法中的逻辑融入到distance方法中。这样可以减少数据结构的使用,提高效率。

      2. 使用HashSet替代boolean数组:使用HashSet替换二维布尔数组vis,以减少空间复杂度,并且查找速度更快。

      3. 使用双向边:当添加新节点时,确保同时将边加入到邻接表的两个方向,这样可以在搜索阶段减少查询次数。

      4. 优化队列结构:使用一个优先队列(基于堆的数据结构),这样可以直接获取最小距离的节点,而不需要每次迭代都遍历整个队列。

      5. 优化距离计算:在添加新节点到队列时,只需存储目标节点的距离,而不是从源节点到目标节点的总距离,这会简化代码并加快搜索过程。

      以下是优化后的代码:

      import java.util.*;
      
      class UserSolution {
      
          class Node implements Comparable {
              int id;
              int x;
              int y;
      
              public Node() {}
      
              public Node(int id) {
                  this.id = id;
              }
      
              @Override
              public int compareTo(Node other) {
                  return Integer.compare(this.x, other.x);
              }
          }
      
          int n;
          int[][] graph;
          HashMap nodeMap = new HashMap<>();
          HashMap> adjTable = new HashMap<>();
          int range;
      
          int[] dx = {1, -1, 0, 0};
          int[] dy = {0, 0, 1, -1};
      
          void init(int N, int mRange, int[][] mMap) {
              this.n = N;
              this.graph = new int[n][n];
              nodeMap.clear();
              adjTable.clear();
              this.range = mRange;
              for (int i = 0; i < n; i++) {
                  for (int j = 0; j < n; j++) {
                      if (mMap[i][j] == 0) {
                          graph[i][j] = -1;
                          continue;
                      }
                      if (mMap[i][j] == 1) {
                          graph[i][j] = -2;
                      }
                  }
              }
          }
      
          void add(int mID, int mRow, int mCol) {
              Node insertNode = new Node(mID);
              nodeMap.put(mID, insertNode);
              graph[mRow][mCol] = mID;
      
              adjTable.putIfAbsent(mID, new HashSet<>());
              adjTable.get(mID).add(insertNode);
      
              for (int i = 0; i < 4; i++) {
                  int newX = mRow + dx[i];
                  int newY = mCol + dy[i];
                  if (isInBounds(newX, newY) && graph[newX][newY] != -2 && graph[newX][newY] > -1) {
                      adjTable.get(graph[newX][newY]).add(insertNode);
                      adjTable.get(mID).add(new Node(graph[newX][newY]));
                  }
              }
          }
      
          private boolean isInBounds(int x, int y) {
              return x >= 0 && y >= 0 && x < n && y < n;
          }
      
          int distance(int mFrom, int mTo) {
              Node sourceNode = nodeMap.get(mFrom);
              Node targetNode = nodeMap.get(mTo);
              if (sourceNode == null || targetNode == null) {
                  return -1;
              }
      
              PriorityQueue queue = new PriorityQueue<>();
              HashSet visited = new HashSet<>();
              queue.offer(sourceNode);
              visited.add(mFrom);
      
              while (!queue.isEmpty()) {
                  Node currentNode = queue.poll();
      
                  if (currentNode.id == mTo) {
                      return currentNode.x;
                  }
      
                  for (Node neighbor : adjTable.get(currentNode.id)) {
                      if (!visited.contains(neighbor.id)) {
                          queue.offer(neighbor);
                          visited.add(neighbor.id);
                      }
                  }
              }
      
              return -1;
          }
      }
      

      这些修改应该能提升算法性能,但请注意,对于非常大的图,可能仍然需要考虑更高效的算法,比如A*搜索或者Dijkstra算法,特别是当存在启发式信息时。

      展开全部

      评论 编辑记录
    • 阿里嘎多学长 2024-04-25 19:46
      关注

      以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


      问题概括

      这个问题的目的是实现一个算法,用于在一个给定的地图上找到从起点 mFrom 到终点 mTo 的最短路径。地图由一个二维数组 mMap 表示,其中 0 表示无障碍,1 表示有障碍。此外,地图上还有一些加油站 station,可以在这些加油站加油,加油后可以行驶 mRange 的距离。

      问题出现原因

      根据提供的信息,问题出现的原因是算法在处理大规模数据或复杂地图时超时。这可能是因为算法的时间复杂度过高,或者数据结构的使用不够高效。

      问题解决方案

      为了优化算法,我们可以考虑以下几点:

      1. 减少重复计算:在 update 方法中,对于每个加油站,都进行了一次完整的广度优先搜索(BFS)来更新邻接表。这可能导致大量的重复计算。可以考虑使用启发式方法或动态规划来减少计算量。
      2. 优化数据结构:当前使用 HashMapArrayList 来存储节点和边,这可能导致在查找和更新时效率不高。可以考虑使用更高效的数据结构,如并查集(Union-Find)来处理连通性问题。
      3. 优先队列优化:在 distance 方法中,使用了 PriorityQueue 来实现 Dijkstra 算法。可以考虑优化这一部分,比如使用 Fibonacci 堆来减少路径查找的时间复杂度。
      4. 并行计算:如果环境支持,可以考虑将某些计算过程并行化,以加快处理速度。

      提供代码

      由于提供的信息不足以完全重写代码,以下是基于现有代码的一些建议性优化:

      // 其他代码保持不变...
      
      private void update(Node updateNode) {
          // 使用并查集来优化连通性判断
          UnionFind uf = new UnionFind(n);
          
          // 从加油站开始 BFS
          ArrayDeque queue = new ArrayDeque<>();
          boolean[][] vis = new boolean[n][n];
          queue.add(new Node(updateNode.id, updateNode.x, updateNode.y, 0));
          vis[updateNode.x][updateNode.y] = true;
          
          while (!queue.isEmpty()) {
              Node startNode = queue.poll();
              
              for (int i = 0; i < 4; i++) {
                  int newX = startNode.x + dx[i];
                  int newY = startNode.y + dy[i];
                  int dist = startNode.dist + 1;
                  if (!isOut(newX, newY) || vis[newX][newY] || dist > range) {
                      continue;
                  }
                  
                  int id = graph[newX][newY];
                  if (id > -2) {
                      // 使用并查集来合并节点
                      uf.union(startNode.id, id);
                      
                      queue.add(new Node(id, newX, newY, dist));
                  }
              }
          }
          
          // 根据并查集的结果更新邻接表
          for (int i = 0; i < n; i++) {
              for (int j = 0; j < n; j++) {
                  int id = graph[i][j];
                  if (id > -2 && uf.find(id) == updateNode.id) {
                      adjTable.get(updateNode.id).add(new Node(id, i, j, uf.getDistance(id)));
                      adjTable.get(id).add(new Node(updateNode.id, updateNode.x, updateNode.y, uf.getDistance(id)));
                  }
              }
          }
      }
      
      // 并查集的实现
      class UnionFind {
          private int[] parent;
          private int[] rank;
          private int[] distance;
      
          public UnionFind(int size) {
              parent = new int[size];
              rank = new int[size];
              distance = new int[size];
              for (int i = 0; i < size; i++) {
                  parent[i] = i;
                  rank[i] = 0;
                  distance[i] = 0;
              }
          }
      
          public int find(int x) {
              if (parent[x] != x) {
                  parent[x] = find(parent[x]);
                  distance[x] = distance[parent[x]] + 1;
              }
              return parent[x];
          }
      
          public void union(int x, int y) {
              int xRoot = find(x);
              int yRoot = find(y);
              if (xRoot == yRoot) {
                  return;
              }
              if (rank[xRoot] < rank[yRoot]) {
                  parent[xRoot] = yRoot;
                  distance[yRoot] = distance[xRoot] + 1;
              } else if (rank[xRoot] > rank[yRoot]) {
                  parent[yRoot] = xRoot;
                  distance[xRoot] = distance[yRoot] + 1;
              } else {
                  parent[yRoot] = xRoot;
                  rank[xRoot]++;
                  distance[xRoot] = distance[yRoot] + 1;
              }
          }
      
          public int getDistance(int x) {
              return distance[find(x)];
          }
      }
      
      // 其他代码保持不变...
      

      示例代码运行方式

      1. 将上述代码复制到 Java 开发环境中。
      2. 确保开发环境已安装 JDK。
      3. 创建一个 UserSolution 类的实例,并调用 init 方法初始化地图。
      4. 使用 add 方法添加加油站。
      5. 调用 distance 方法计算最短距离。

      示例代码预期运行结果

      由于没有具体的输入数据,无法提供确切的运行结果。但是,上述代码优化了原始算法,应该能够提高处理速度并减少超时的情况。

      参考链接

      展开全部

      评论 编辑记录
    • Kwan的解忧杂货铺 Java领域优质创作者 2024-04-25 19:46
      关注

      晚上好🌙🌙🌙
      本答案参考ChatGPT-3.5

      问题描述:

      给定一个地图并描述初始状态,其中0表示无障碍,1表示障碍物。程序需要支持增加加油站,并给定能行驶的范围。最后需要求出最短路径,从mFrom到mTo(对应add函数的mId)。

      目前的问题:

      你已经给出了要求,但程序会超时。希望你能进一步优化。

      解决方案:

      1. Dijkstra算法的优化

      主要思路是对于在队列中的节点进行更新操作,防止队列中会存储过多的节点。

      (1)使用优先队列存储节点。

      (2)使用vis数组,表示某个节点是否在优先队列中。

      (3)在每次更新节点后将其重新加入队列。如果节点已经在队列中,则更新其权值,否则将其加入队列。

      ~具体实现可以参考其他题解~

      1. A*算法

      在Dijkstra算法的基础上,A*算法会使用启发式函数,对于已经找到的路径进行小幅度的调整,使得搜索过程更加高效。

      主要思路是在Dijkstra算法的基础上,加入启发式函数,用以评估某个节点到达目标节点的最小距离。

      具体实现可以参考其他资料。

      1. 针对当前程序的优化

      目前程序中很多重复的操作,可以进行优化来减少耗费时间的操作。

      (1)在update函数中,当更新一个节点时,可以直接将该节点到其他所有节点的最短距离都计算出来,因为整个地图的障碍物是不变的。

      (2)在update函数中,可以对于新加入的节点,只计算从已有节点到该节点的距离,可以减少不必要的遍历。

      (3)在distance函数中,可以采用数组代替HashMap,因为地图的大小是已知的且较小的。

      (4)在distance函数中,可以采用数组代替bool数组来判断节点是否被访问过。

      修改后的代码如下:

      class UserSolution { int n; int[][] graph; Node[] nodeArray; ArrayList[] adjTable; int range;

      int[] dx = new int[]{1, -1, 0, 0};
      int[] dy = new int[]{0, 0, 1, -1};
      
      void init(int N, int mRange, int[][] mMap) {
          this.n = N;
          this.graph = new int[n][n];
          nodeArray = new Node[N * N];
          adjTable = new ArrayList[N * N];
          this.range = mRange;
          for (int i = 0; i < n; i++) {
              for (int j = 0; j < n; j++) {
                  int index = i * n + j;
                  if (mMap[i][j] == 0) {
                      nodeArray[index] = new Node(-1);
                      graph[i][j] = -1;
                      continue;
                  }
                  if (mMap[i][j] == 1) {
                      nodeArray[index] = new Node(-2);
                      graph[i][j] = -2;
                  }
              }
          }
          for (int i = 0; i < N * N; i++) {
              adjTable[i] = new ArrayList<>();
          }
      }
      
      void add(int mID, int mRow, int mCol) {
          int index = mRow * n + mCol;
          nodeArray[index] = new Node(mID, mRow, mCol);
          graph[mRow][mCol] = mID;
          int mid = nodeArray[index].id;
          for (int i = 0; i < 4; i++) {
              int newRow = mRow + dx[i];
              int newCol = mCol + dy[i];
              if (isOut(newRow, newCol)) {
                  int newIndex = newRow * n + newCol;
                  int adjacentNode = nodeArray[newIndex].id;
                  if (adjacentNode == -2) {
                      continue;
                  }
                  int dist = getDist(mRow, mCol, newRow, newCol);
                  adjTable[mid].add(new Node(adjacentNode, newRow, newCol, dist));
                  adjTable[adjacentNode].add(new Node(mid, mRow, mCol, dist));
              }
          }
      }
      
      int distance(int mFrom, int mTo) {
          Node sourceNode = nodeArray[mFrom];
          Node targetNode = nodeArray[mTo];
          if (sourceNode == null || targetNode == null) {
              return -1;
          }
          int[] dis = new int[n * n];
          Arrays.fill(dis, Integer.MAX_VALUE);
          boolean[] vis = new boolean[n * n];
          PriorityQueue queue = new PriorityQueue<>(new NodeComparator());
          queue.offer(sourceNode);
          vis[sourceNode.id] = true;
          dis[sourceNode.id] = 0;
          while (!queue.isEmpty()) {
              Node node = queue.poll();
              vis[node.id] = false;
              for (Node adjacent : adjTable[node.id]) {
                  int d = dis[node.id] + adjacent.dist;
                  if (d < dis[adjacent.id]) {
                      dis[adjacent.id] = d;
                      if (!vis[adjacent.id]) {
                          queue.offer(nodeArray[adjacent.id]);
                          vis[adjacent.id] = true;
                      }
                  }
              }
          }
          return dis[mTo] != Integer.MAX_VALUE ? dis[mTo] : -1;
      }
      
      private int getDist(int x1, int y1, int x2, int y2) {
          return Math.abs(x1 - x2) + Math.abs(y1 - y2);
      }
      
      private boolean isOut(int x, int y) {
          return x >= 0 && y >= 0 && x < n && y < n;
      }
      
      class Node {
          int id;
          int x;
          int y;
          int dist;
      
          public Node(int id) {
              this.id = id;
          }
      
          public Node(int id, int x, int y) {
              this.id = id;
              this.x = x;
              this.y = y;
          }
      
          public Node(int id, int x, int y, int dist) {
              this.id = id;
              this.x = x;
              this.y = y;
              this.dist = dist;
          }
      }
      
      class NodeComparator implements Comparator {
          @Override
          public int compare(Node o1, Node o2) {
              return o1.dist - o2.dist;
          }
      }
      

      }

      要点说明:

      (1)使用一个Node数组存储所有节点,避免通过HashMap进行节点的查找。

      (2)在add函数中,加入新加入的节点时,只计算从已有节点到该节点的距离,避免进行不必要的遍历。

      (3)在distance函数中,使用数组代替HashMap,使用数组代替bool数组进行节点访问状态判断。

      展开全部

      评论
    编辑
    预览

    报告相同问题?

  • 相关阅读:
    基于 Python 的地理空间绘图(附源码)
    【mcuclub】四相五线步进电机
    前端开发之ES6(ECMAscript6)语法以及ES6++快速学习入门(前端必备了解知识)
    Python | 机器学习之PCA降维
    输出调节求解跟踪问题(二阶线性系统)
    [go 面试] 分布式事务框架选择与实践
    STP、堆叠与VRRP如何使用
    第一章:认识Qt 之 1.2 Qt发展历史
    回应张逸老师(一)圈子文化
    多段曲线控温“核函数“算法分析(完整梯形图源代码)
  • 原文地址:https://ask.csdn.net/questions/8094946