欢迎光临
我们一直在努力

最短路总结

分层图

将原问题中的额外状态(如剩余步数、资源数量、模数等)作为 “ 层 ” 来扩展图,从而将复杂约束转化为普通的最短路问题。

算法核心思想适用时间复杂度能否处理负权边能否处理负环
Dijkstra 贪心:从起点开始,每次从未钉死最短路的点中选取距离最近的点,并用它去“松弛”其邻接点 单源最短路,非负权图 O(m log n) 不能 不能
Bellman-Ford 暴力枚举边:对所有边进行 n-1 次松弛操作,每次尝试更新所有边终点的距离 单源最短路,存在负权边的有向图 O(nm)
SPFA 队列优化 BF:是 Bellman-Ford 算法的队列优化版,只对“被成功松弛”的点的出边进行松弛,避免了无效的边遍历 单源最短路,存在负权边的有向图 平均 O (km),最坏 O (nm)
Floyd 区间 DP:通过枚举中间点 k 来松弛任意两点 i、j 之间的距离 多源最短路,稠密图 O(n³) 有向图可以处理
Johnson 贪心:通过一次 SPFA 来判断负环,然后跑 n 遍 Dijkstra 多源最短路,稀疏图 O(n² log n + nm)

最短路模版

//Dijkstra
const int maxn = 100010;
struct node {
   int dis, pos;
   bool operator<(const node &x) const { return x.dis < dis; }
};
int n, m, s, t;
int dis[maxn];
bool vis[maxn];
vector<pair<int, int>> g[maxn];
priority_queue<node> q;
void dijkstra() {
   for (int i = 1; i <= n; i++) {
       dis[i] = 0x3f3f3f3f;
       vis[i] = 0;
  }
   dis[s] = 0;
   q.push({ 0, s });
   while (!q.empty()) {
       node tmp = q.top();
       q.pop();
       int x = tmp.pos;
       if (vis[x]) {
           continue;
      }
       vis[x] = 1;
       for (auto [y, w] : g[x]) {
           if (dis[y] > dis[x] + w) {
               dis[y] = dis[x] + w;
               if (!vis[y]) {
                   q.push({ dis[y], y });
              }
          }
      }
  }
}

//SPFA
const int maxn = 1e4 + 5;
const int inf = 1e9;
int n, m, s, u, v, w, t;
int dis[maxn];
bool vis[maxn];
vector<pair<int, int>> g[maxn];
void spfa() {
   for (int i = 1; i <= n; i++) {
       dis[i] = inf;
  }
   queue<int> q;
   q.push(s);
   vis[s] = 1;
   dis[s] = 0;
   while (!q.empty()) {
       int t = q.front();
       q.pop();
       vis[t] = 0;
       for (int i = 0; i < g[t].size(); i++) {
           int to = g[t][i].first;
           int w = g[t][i].second;
           if (dis[to] > dis[t] + w) {
               dis[to] = dis[t] + w;
               if (vis[to]) {
                   continue;
              }
               vis[to] = 1;
               q.push(to);
          }
      }
  }
}

//Floyd
for (int k = 1; k <= n; k++) {
       for (int i = 1; i <= n; i++) {
           for (int j = 1; j <= n; j++) {
               dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
          }
      }
  }

//Johnson
const int maxn = 3e3 + 5;
const int INF = 1e9;
struct node {
   int dis;
   int pos;
   bool operator<(const node& oth) const { return dis > oth.dis; }
};
int n, m;
vector<pair<int, int> > g[maxn];
vector<pair<int, int> > g2[maxn];
int dis[maxn];
int cnt[maxn];
bool inq[maxn];
int h[maxn];
int ans[maxn][maxn];
bool SPFA(int s) {
   queue<int> q;
   for (int i = 0; i <= n; i++) {
       dis[i] = INF;
       cnt[i] = 0;
       inq[i] = 0;
  }
   dis[s] = 0;
   inq[s] = 1;
   q.push(s);
   while (!q.empty()) {
       int u = q.front();
       q.pop();
       inq[u] = 0;
       for (auto v : g[u]) {
           int nod = v.first;
           int w = v.second;
           if (dis[u] + w < dis[nod]) {
               dis[nod] = dis[u] + w;
               if (!inq[nod]) {
                   q.push(nod);
                   inq[nod] = 1;
                   cnt[nod]++;
                   if (cnt[nod] > n) {
                       return 0;
                  }
              }
          }
      }
  }
   for (int i = 1; i <= n; i++) {
       h[i] = dis[i];
  }
   return 1;
}
void dijkstra(int s) {
   priority_queue<node> q;
   for (int i = 1; i <= n; i++) dis[i] = INF;
   memset(inq, 0, sizeof(inq));
   dis[s] = 0;
   q.push({ 0, s });
   while (!q.empty()) {
       int u = q.top().pos;
       q.pop();
       if (inq[u])
           continue;
       inq[u] = 1;
       for (auto v : g2[u]) {
           int nod = v.first;
           int w = v.second;
           if (dis[nod] > dis[u] + w) {
               dis[nod] = dis[u] + w;
               if (!inq[nod]) {
                   q.push({ dis[nod], nod });
              }
          }
      }
  }
   for (int i = 1; i <= n; i++) {
       if (dis[i] >= INF) {
           ans[s][i] = INF;
      } else {
           ans[s][i] = dis[i] – h[s] + h[i];
      }
  }
}

赞(0)
未经允许不得转载:171主机测评 » 最短路总结
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址