使用负循环计算图中节点之间的距离(双溢出)

时间:2017-04-13 09:12:27

标签: c++ algorithm graph double bellman-ford

完全披露:这是一个在线课程。

代码使用Bellman-Ford算法计算图表中起始节点与所有其他节点之间的距离。图形可能包含负循环:在这种情况下,输出应使用“ - ”表示该距离。如果起始节点和另一个节点之间没有链接,它应该是'*'。否则,它应该输出距离。

代码正在运行,但我相信存在溢出问题,我不知道如何解决。约束指定以下最大值:

  • 节点:10 ^ 3;
  • 边缘:10 ^ 4;
  • 边缘重量:10 ^ 9

测试所有与逻辑相关的极端情况导致没有问题,一切正常。失败的测试(很可能)与溢出有关。

代码

void bfs(vector<vector<int> > &adj, queue<int> q, vector<bool> &shortest) {
  int size = adj.size();
  vector<bool> visited(size, false);
  while (!q.empty()) {
    int v = q.front();
    if (visited[v]) {
      q.pop();
    } else {
      q.pop();
      for (int i = 0; i < adj[v].size(); i++) {
        shortest[adj[v][i]] = true;
        q.push(adj[v][i]);
      }
    }
    visited[v] = true;
  }
}

void shortest_paths(vector<vector<int> > &adj, vector<vector<int> > &cost, int s, 
  vector<double> &distance, vector<bool> &reachable, vector<bool> &shortest) {
  int size = adj.size();
  distance[s] = 0;
  reachable[s] = true;
  queue<int> negative_cycle;
  // Set initial distances and get negative cycles
  for (int i = 0; i <= size; i++) {
    for (int j = 0; j < size; j++) {
      for (int k = 0; k < adj[j].size(); k++) {
        // Edge relaxation
        if (distance[adj[j][k]] > distance[j] + cost[j][k]) {
          reachable[adj[j][k]] = true;
          if (i == size) {
            // Store negative cycles
            negative_cycle.push(adj[j][k]);
            shortest[adj[j][k]] = true;
          }
          distance[adj[j][k]] = distance[j] + cost[j][k];
        }
      }
    }
  }
  bfs(adj, negative_cycle, shortest);
}

和主

int main() {
  int n, m, s;
  std::cin >> n >> m;
  vector<vector<int> > adj(n, vector<int>());
  vector<vector<int> > cost(n, vector<int>());
  for (int i = 0; i < m; i++) {
    double x, y, w;
    std::cin >> x >> y >> w;
    adj[x - 1].push_back(y - 1);
    cost[x - 1].push_back(w);
  }
  std::cin >> s;
  s--;
  vector<double> distance(n, std::numeric_limits<double>::infinity());
  vector<bool> reachable(n, false);
  vector<bool> shortest(n, false);
  shortest_paths(adj, cost, s, distance, reachable, shortest);
  for (int i = 0; i < n; i++) {
    if (!reachable[i]) {
      std::cout << "*\n";
    } else if (shortest[i]) {
      std::cout << "-\n";
    } else {
      std::cout << distance[i] << "\n";
    }
  }
}

我正在使用double和infinity,因为算法需要它(你可以阅读它here)。从我已经完成的谷歌搜索,我得到这不应该溢出,因为最大可能的距离将是10 ^ 4 * 10 ^ 9 = 10 ^ 13,这仍然是在双倍的跨度内。我没有太多经验使用这样的无限或双打,从我研究过的内容我无法追踪问题。

是否有使用双无穷大的替代方法(因为long long没有它并且它的max_size不能在问题的上下文中使用)?在这种情况下是否会出现双重溢出或其他相关问题(比较失败等)?

0 个答案:

没有答案