RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1381252
Accepted
Rennorb
Rennorb
Asked:2022-07-12 18:46:27 +0000 UTC2022-07-12 18:46:27 +0000 UTC 2022-07-12 18:46:27 +0000 UTC

是否有可能以某种方式加速 Dijkstra 算法的实现?

  • 772

我对“graph”类的实现,PathWeights方法实现了 Dijkstra 的有向加权图算法:

const int HUGE_NUMBER = 100000000; //

typedef std::pair<int, uint64_t> Arrow;

bool ArrowCmp(const Arrow &lhs, const Arrow &rhs) {
  return lhs.first < rhs.first;
}

class Graph {
  int size_;

  std::vector<std::vector<Arrow>> arrows;
  std::vector<int> parents;

 public:
  explicit Graph(int size) {
    size_ = size;
    arrows.resize(size);
    parents.resize(size);
  }

  void AddEdge(int from, int to, uint64_t cost) {
    if (from == to) {
      return;
    }

    auto arrow = std::make_pair(to, cost);

    auto pos = std::lower_bound(arrows[from].begin(),
                                arrows[from].end(),
                                arrow,
                                ArrowCmp);

    if (pos == arrows[from].end()) {
      arrows[from].push_back(arrow);
    } else if (pos->first != arrow.first) {
      arrows[from].insert(pos, arrow);
    } else {
      (*pos).second = std::min(cost, pos->second);
    }
  }

  std::vector<int> Path(int from, int to) {
    PathWeights(from);

    std::vector<int> ret;

    for (int cv = to; cv != from; cv = parents[cv]) {
      ret.push_back(cv);
    }

    ret.push_back(from);
    std::reverse(ret.begin(), ret.end());

    return ret;
  }

  std::vector<uint64_t> PathWeights(int start) {
    std::vector<uint64_t> lens(size_);

    std::fill(lens.begin(), lens.end(), HUGE_NUMBER);
    lens[start] = 0;

    int count = 0;

    std::set<std::pair<uint64_t, int>> sorted_ps;

    sorted_ps.insert(std::make_pair(0, start));

    while (!sorted_ps.empty()) {
      int from = sorted_ps.begin()->second;
      sorted_ps.erase(sorted_ps.begin());

      for (int to = 0; to < size_; ++to) {
        auto arrow = std::make_pair(to, 0ul);
        auto pos = std::lower_bound(arrows[from].begin(),
                                    arrows[from].end(),
                                    arrow,
                                    ArrowCmp);

        if (pos == arrows[from].end()) {
          continue;
        }

        if (pos->first != to) {
          continue;
        }

        auto cost = pos->second;

        if (lens[from] + cost < lens[to]) {
          sorted_ps.erase(std::make_pair(lens[to], to));
          lens[to] = lens[from] + cost;
          parents[from] = to;
          sorted_ps.insert(std::make_pair(lens[to], to));
        }
      }
      ++count;
    }

    return lens;
  }
};

我正在尝试从封闭式比赛中解决问题,问题的条件可以表述如下:

  1. 给定一个可以有环和多条边的有向加权图
  2. 权重是从零到二的整数
  3. 顶点少于 5000,边少于 20000
  4. 找到两个给定顶点之间最简单路径的权重
  5. Main对 PathWeights 的调用不超过 10000次
  6. 程序应使用不超过 64Mb 的内存,运行不超过 3 秒

现在程序可以正常工作,但速度很慢。

第一个解决方案将边存储为邻接矩阵,并使用布尔数组通过线性搜索来搜索合适的顶点。现在我正在使用传出边的向量,按升序结束顶点索引排序,并设置为选择适当的顶点。有没有其他方法可以加快这个解决方案?在这些条件下是否值得使用另一种算法?

c++
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Karashevich B.
    2022-07-12T22:43:57Z2022-07-12T22:43:57Z

    这个地方显然有问题:

       for (int to = 0; to < size_; ++to) {
         auto arrow = std::make_pair(to, 0ul);
         auto pos = std::lower_bound(arrows[from].begin(),
                                     arrows[from].end(),
                                     arrow,
                                     ArrowCmp);
    

    我们有一个通过图的所有顶点的线性传递,加上一个 binsearch,在这里它足以遍历arrows[from]. 就时间复杂度而言,这显然是这段代码的主要问题。

    我还注意到一条线parents[from] = to;——绝对不是相反?

    我还建议您对 AddEdge 进行基准测试。我有一个模糊的怀疑,所有这些插入向量中间的操作都会严重降低性能。我从来不需要在边缘列表中维护不变的“传出边缘已排序”。也许摆脱它会更好?他为什么在这里?

    • 2
  2. Best Answer
    Rennorb
    2022-07-14T15:13:28Z2022-07-14T15:13:28Z

    以防万一,以下想法可以显着提高性能:

    1. 到当前正在处理的顶点的距离 L 大于或等于所有之前的距离
    2. 新的最小距离在集合 {L, L+1, L+1} 中。

    这允许我们放弃集合并使用三个向量,每个向量都有自己的距离,并使用 得到一个新顶点.end(); .pop_back(),这似乎将 O(V+E log E) 简化为 O(V+E)。

    • 0

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5