算法训练1-day52-图论

16 阅读3分钟
  1. 97. 小明逛公园

Floyd算法解决的是全源最短路径问题,即计算图中任意两个节点之间的最短路径;基于动态规划。通过考虑所有节点作为中间节点的可能性,来系统地更新任意两点间的最短距离。

  • 时间复杂度O(n3)O(n^3),空间复杂度O(n2)O(n^2),适用于任何图,不论有向无向、不管边权值正负,但不能有负环(即保证最短路存在)
  • 考察从i到j的距离distance[i][j]能不能通过一个中间点bridge来缩短,即distance[i][j]是否小于distance[i][bridge]+ distance[bridge][j]
#include <climits>
#include <iostream>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

int main() {
  int n, m;
  cin >> n >> m;

  int defaultValue = 10001;
  vector<vector<int>> grid(n + 1, vector<int>(n + 1, defaultValue));

  int from, to, weight;
  for (int i = 0; i < m; ++i) {
    cin >> from >> to >> weight;
    grid[from][to] = weight;
    grid[to][from] = weight;
  }

  for (int bridge = 1; bridge <= n; ++bridge) {
    for (int i = 1; i <= n; ++i) {
      for (int j = 1; j <= n; ++j) {
        if (grid[i][bridge] != defaultValue &&
            grid[bridge][j] != defaultValue &&
            grid[i][j] > grid[i][bridge] + grid[bridge][j]) {
          grid[i][j] = grid[i][bridge] + grid[bridge][j];
        }
      }
    }
  }
  int Q = 0;
  cin >> Q;
  int start, end;
  for (int i = 0; i < Q; ++i) {
    cin >> start >> end;
    cout << (grid[start][end] == defaultValue ? -1 : grid[start][end]) << endl;
  }

  return 0;
}

  1. 127. 骑士的攻击

指定源点、指定目标点,求源点到目标点的最短距离。 增加了当前点到终点的预估距离 加入小根堆时,用的是源点到当前点的距离+当前点到终点的预估距离 其余与Dijkstra算法相同 A* 算法是一种启发式搜索算法,主要用于在静态图中寻找单一目标点的最短路径。它是对Dijkstra算法的优化,通过引入一个启发式函数来指导搜索方向。在Dijkstra的基础上,不仅考虑从源点到当前节点的实际代价 g(n),还估计从当前节点到目标节点的预计代价 h(n)。它总是优先选择 f(n) = g(n) + h(n) 值最小的节点进行扩展。 预估函数一般选择:曼哈顿距离,欧式距离,对角线距离

#include <climits>
#include <cstring>
#include <iostream>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

const int m = 1000;
int moves[1001][1001];

class Knight {
public:
  int x;
  int y;
  int g, h, f;

  // 从小到大
  bool operator<(const Knight &k) const { return k.f < f; }
};
priority_queue<Knight, vector<Knight>> pq;
int h(int a1, int a2, int b1, int b2) {
  return (b1 - a1) * (b1 - a1) + (b2 - a2) * (b2 - a2);
}
int dirs[8][2] = {-2, -1, -2, 1, -1, 2, 1, 2, 2, 1, 2, -1, 1, -2, -1, -2};
int Astar(int a1, int a2, int b1, int b2) {
  Knight cur, next;
  while (!pq.empty()) {
    cur = pq.top();
    pq.pop();
    if (cur.x == b1 && cur.y == b2)
      break;
    for (auto dir : dirs) {
      next.x = cur.x + dir[0];
      next.y = cur.y + dir[1];
      if (next.x < 1 || next.x > m || next.y < 1 || next.y > m) {
        continue;
      }
      if (!moves[next.x][next.y]) {
        moves[next.x][next.y] = moves[cur.x][cur.y] + 1;
        next.g = cur.g + 5;
        next.h = h(next.x, next.y, b1, b2);
        next.f = next.g + next.h;
        pq.push(next);
      }
    }
  }
  return moves[b1][b2];
}

int main() {

  int n;
  cin >> n;

  int a1, a2, b1, b2;
  for (int i = 0; i < n; ++i) {
    cin >> a1 >> a2 >> b1 >> b2;
    memset(moves, 0, sizeof(moves));
    Knight knight;
    knight.x = a1;
    knight.y = a2;
    knight.g = 0;
    knight.h = h(a1, a2, b1, b2);
    knight.f = knight.g + knight.h;
    pq.push(knight);
    cout << Astar(a1, a2, b1, b2) << endl;
    while (!pq.empty()) {
      pq.pop();
    }
  }
  return 0;
}

算法训练1-day51-图论