c++ - 最短路径算法太慢

标签 c++ performance algorithm path-finding

<分区>

我正在用最短路径算法解决一个问题,但它太慢了,问题是我有 N 个点,只有当它们之间的距离小于或等于 D 时才能连接,我有起始索引和完成(代码中的“ciel”)索引并且必须以双格式返回最短路径。一开始觉得是sqrt太慢了,后来改了还是太慢了。我正在回溯距离并在那里使用 sqrt 以获得更好的速度,但它太慢了。我使用了优先级队列。有关更多信息,输入包括点的 X 和 Y、D 到边缘的最大距离、起始索引和结束索引。最多可以有 1000 个点。

这是我的代码 http://pastebin.com/pQS29Vw9请问有什么办法可以让它更快吗?

#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <utility>

using namespace std;

const int MAX = 1001;
const int INF = 1e9;

std::vector< std::pair<int, int> > edges[MAX]; // hrany a vzdialenosti medzi bodmi a hranami
int N; // pocet vrcholov
int start, ciel; // start a ciel index

double dijkstra() {
        int vis[N]; // pocet navstiveni daneho bodu
        int prevNodes[N][2];
        for(int i=0;i < N;i++)
        prevNodes[i][1] = INF;

        std::priority_queue< std::pair<int, int> > heap; // halda
        for(int i = 0; i < N; i++) vis[i] = 0;
        heap.push(pair<int, int>(0, start));
        while(!heap.empty())
    {
                pair<int, int> min = heap.top(); // vybratie dalsieho
                heap.pop(); // vyhodenie pozreteho
                min.first *= -1.0; // kvoli spravnemu fungovaniu priority
                int v = min.second; // len pre oko

                vis[v]++;
                if (v == ciel && vis[v] == 1)
        {
            double d = 0.0;

            int prevIndex = ciel, nextIndex = prevNodes[ciel][0];

            while(1)
            {

                for(int j=0;j < edges[nextIndex].size();j++)
                    if(edges[nextIndex][j].first == prevIndex)
                    {

                        d += sqrt(double( edges[nextIndex][j].second ));
                        break;
                    }

                prevIndex = nextIndex; // posunutie
                if(nextIndex == start) // ak sme uz na zaciatku
                    break;
                else
                    nextIndex = prevNodes[nextIndex][0];// posun dalej
            }
                        return d; // najkratsia cesta
        }

                for (int i = 0; i < (int) edges[v].size(); i++)
        {
                        if (vis[edges[v][i].first] < 1)
            {
                if(prevNodes[edges[v][i].first][1] > min.first + edges[v][i].second)
                {
                    prevNodes[edges[v][i].first][0] = min.second;

                    prevNodes[edges[v][i].first][1] = min.first + edges[v][i].second;
                }
                                heap.push(pair<int, int>(-(min.first + edges[v][i].second), edges[v][i].first));
            }
                }
        }
        return -1;
}

int main()
{
    int X;
    scanf("%d",&X);
    double answers[X];
    for(int i=0;i < X;i++)
    {
        int D, sIndex, eIndex; // N je globalne
        scanf("%d %d", &N, &D); // N
        int DD = D * D;
        for(int j=0;j < N;j++)
            edges[j].clear();

        int V[N][2]; // N
        int x, y;
        for(int k=0;k < N;k++) // N
        {
            scanf("%d %d", &x, &y);
            V[k][0] = x;
            V[k][1] = y;
        }

        for(int a=0;a < N;a++)
            for(int b=0;b < N;b++)
            {

                int v = (((V[a][0] - V[b][0]) * (V[a][0] - V[b][0]) +
                                (V[a][1] - V[b][1]) * (V[a][1] - V[b][1])));
                if(v > DD)
                    continue;
                else
                {
                    edges[a].push_back(pair<int, int>(b, v));
                    edges[b].push_back(pair<int, int>(a, v));
                }
            }

        scanf("%d %d", &start, &ciel);
        start--;
        ciel--;
        double dijLen = dijkstra();
        if(dijLen < 0)
            answers[i] = -1;
        else
            answers[i] = dijLen;
    }
    for(int i=0;i < X;i++)
        if(answers[i] < 0)
            printf("Plan B\n");
        else
            printf("%.2f\n", answers[i]);

    return 0;
}

最佳答案

需要考虑的三种可能的算法改进:

改进搜索

Djikstra 算法将探索起点节点 S 内的所有点,其中 S 是起点和终点之间的最短距离。

如果您使用 A* search (例如,使用到目标的欧几里得距离的启发式方法)那么您应该会发现需要探索的点要少得多。

边缘构建的改进

根据点的分布方式,您可能会发现通过以下方式找到距离 D 内的边会更好:

  1. 想象一个边长为 D 的网格覆盖在平面上
  2. 将每个点加入到它所属的网格正方形对应的桶中
  3. 当你需要找到一个点的邻居时,你只需要测试相邻桶中的点而不是每个点。

改进预处理

根据点的分布,您可能会发现当到达顶点时仅构建有效边比预先计算所有边更有效。

如果起点和目的地很近,这可能会节省很多时间。

关于c++ - 最短路径算法太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21684607/

相关文章:

c++ - 位操作

c++ - C++ 中 std::reference_wrapper 和类型的编译器错误

algorithm - 大 O 表示法中的 n 是什么?

c++ - 使用 ncurses 显示 wchar_t

c++ - unique_ptr、自定义删除器和零规则

performance - 如何计算CPU的理论峰值性能

android - GPU Overdraw 不适用于我在 Android 上的 apk

multithreading - 原子内存排序性能差异

algorithm - OCR:根据最后 N 个结果选择最佳字符串(OCR 自适应过滤器)

c++ - 为什么C++标准要求std::partition来满足不同类型迭代器的不同复杂度?