【问题标题】:Dijkstra shortest path algorithm doesn't work correctly with large numbers C++Dijkstra 最短路径算法不适用于大量 C++
【发布时间】:2020-08-20 18:39:42
【问题描述】:

我正在尝试使用优先级队列使 Dijkstra 最短路径算法适用于具有平行边的加权无向图的大数。我有内存 (64Mb) 和时间 (1 秒) 限制。问题是当图表很大时它给出了错误的答案。我知道这是因为有一个平台(由我的大学制作),其中一个程序正在测试,它在第 13 次测试中显示错误答案占用的内存比以前的测试要多。

typedef unsigned long int vertex_t;
typedef unsigned long int weight_t;

const weight_t max_weight = 1000000000;

struct neighbor 
{
    vertex_t target;
    weight_t weight;
    neighbor(vertex_t arg_target, weight_t arg_weight)
        : target(arg_target), weight(arg_weight) { }
};

typedef pair<weight_t, vertex_t> weight_vertex_pair_t;

void ShortestPath(vertex_t source, vertex_t target, 
                    const vector<vector<neighbor> > &adjacency,
                    vector<weight_t> &min_distance, vector<vertex_t> &previous)
{
    int n = adjacency.size();
    min_distance.clear();
    min_distance.resize(n, max_weight);
    min_distance[source] = 0;
    previous.clear();
    previous.resize(n, -1);
    priority_queue<weight_vertex_pair_t, vector<weight_vertex_pair_t>,
            greater<weight_vertex_pair_t> > vertex_queue;
    vertex_queue.push(make_pair(min_distance[source], source));

    while (!vertex_queue.empty()) 
    {
        weight_t dist = vertex_queue.top().first;
        vertex_t u = vertex_queue.top().second;
        if (u == target)
        {
            cout << min_distance[u];
            break;
        }
        vertex_queue.pop();

        if (dist > min_distance[u])
            continue;

        const vector<neighbor> &neighbors = adjacency[u];
        for (vector<neighbor>::const_iterator neighbor_iter = neighbors.begin();
             neighbor_iter != neighbors.end();
             neighbor_iter++)
        {
            vertex_t v = neighbor_iter->target;
            weight_t weight = neighbor_iter->weight;
            weight_t u_distance = dist + weight;
            if (u_distance < min_distance[v]) 
            {
                min_distance[v] = u_distance;
                previous[v] = u;
                vertex_queue.push(make_pair(min_distance[v], v));
            }
        }
    }
}

我在 main 中也有这个 while 循环来填充图表。顶点数从 1 开始,这就是我减一的原因。

while (y < edges)
{
     cin >> a >> b >> c; // vertex, neighbor, weight
     adjacency[a-1].push_back(neighbor(b-1, c));
     adjacency[b-1].push_back(neighbor(a-1, c));
     y += 1;
}

【问题讨论】:

  • 这是 32 位还是 64 位代码?你的无符号长的大小是多少?我问是因为你的体重太大了,几乎不适合 32 位的值。确保打开编译器警告。
  • 基本上,如果一个 32 位值并进行任何类型的乘法或除法,甚至在该大小上进行大加法,您可能会溢出您的值。
  • 图大小和成本的限制是多少?
  • 是的,如果你有很多这样的大数字边,你就会超出 32 位整数的范围。

标签: c++ priority-queue shortest-path dijkstra


【解决方案1】:

让我们把它作为一个答案,因为它似乎已经达成共识:

您的 max_weight 值 1,000,000,000 正好位于 32 位有符号整数(2^31 或大约 2,000,000,000)的边缘。如果您对这个错误的数字进行任何类型的乘法或除法,您将溢出 32 位变量。即使在那个比例下加减也可能导致溢出。

所以,你可以:

  • 将所有尺寸缩小相当多,如果您进行较大的乘法或除法,可能会低于 2^15。
  • 使用 64 位数学来确保保留您的精度。对于 64 位,编译器可能会为您处理此问题,但运行速度会较慢。
  • 如果您不需要完美的比较精度,则可以使用浮点数,因为它可以跨越更大的范围,但会以精度为代价。

一般来说: 仔细检查 sizeof() 以确保您的类型大小并确保启用编译器警告,因为它们会捕获任何静态编译时间溢出。

【讨论】:

    猜你喜欢
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    • 2016-07-30
    • 2021-04-18
    相关资源
    最近更新 更多