基础算法——搜索与图论

瑞星  金牌会员 | 2024-12-8 00:54:28 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 802|帖子 802|积分 2406

图的存储方式


2、最短路问题

最短路问题可以分为单源最短路问题和多源最短路问题,单源最短路问题就是求出从点1->n的最短隔断,而多源最短路问题就是求出从点i->j的最短隔断。单源最短路问题还可以分为正权边的单源最短路问题和负权边的单源最短路问题。具体算法和时间复杂度如下图:

2.1、Dijkstra算法(朴素版)


算法模板:
  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. const int N = 510;
  5. int g[N][N], d[N];
  6. int n, m;
  7. bool st[N];
  8. int dijkstra()
  9. {
  10.     memset(d, 0x3f, sizeof d);
  11.     d[1] = 0;
  12.     for (int i = 0; i < n; i++)
  13.     {
  14.         int t = -1;
  15.         for (int j = 1; j <= n; j++)
  16.             if (!st[j] && (t == -1 || d[t] > d[j]))
  17.                 t = j;
  18.         st[t] = true;
  19.         for (int j = 1; j <= n; j++)
  20.             d[j] = min(d[j], d[t] + g[t][j]);
  21.     }
  22.     return d[n] == 0x3f3f3f3f ? -1 : d[n];
  23. }
  24. int main()
  25. {
  26.     cin >> n >> m;
  27.     memset(g, 0x3f, sizeof g);
  28.     while (m--)
  29.     {
  30.         int a, b, c;
  31.         scanf("%d%d%d", &a, &b, &c);
  32.         g[a][b] = min(g[a][b], c);
  33.     }
  34.     cout << dijkstra() << endl;
  35.     return 0;
  36. }
复制代码
2.2、Dijkstra算法(堆优化版)

下面来看看怎样优化:

算法模板:
  1. #include <iostream>
  2. #include <cstring>
  3. #include <queue>
  4. using namespace std;
  5. typedef pair<int, int> PII;
  6. const int N = 1.5e5+10;
  7. int h[N], e[N], w[N], ne[N], idx;
  8. int n, m, d[N];
  9. bool st[N];
  10. void add(int a, int b, int c)
  11. {
  12.     e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
  13. }
  14. int dijkstra()
  15. {
  16.     memset(d, 0x3f, sizeof d);
  17.     d[1] = 0;
  18.     priority_queue<PII, vector<PII>, greater<PII>> heap;
  19.     heap.push({0, 1});
  20.     while (heap.size())
  21.     {
  22.         auto t = heap.top();
  23.         heap.pop();
  24.         int ver = t.second, dis = t.first;
  25.         if (st[ver]) continue;
  26.         st[ver] = true;
  27.         for (int i = h[ver]; i != -1; i = ne[i])
  28.         {
  29.             int j = e[i];
  30.             if (d[j] > dis + w[i])
  31.             {
  32.                 d[j] = dis + w[i];
  33.                 heap.push({d[j], j});
  34.             }
  35.         }
  36.     }
  37.     return d[n] == 0x3f3f3f3f ? -1 : d[n];
  38. }
  39. int main()
  40. {
  41.     cin >> n >> m;
  42.     memset(h, -1, sizeof h);
  43.     while (m--)
  44.     {
  45.         int a, b, c;
  46.         scanf("%d%d%d", &a, &b, &c);
  47.         add(a, b, c);
  48.     }
  49.     cout << dijkstra() << endl;
  50.     return 0;
  51. }
复制代码
2.3、Bellman-Ford算法


代码模板:
  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. const int N = 510, M = 10010;
  5. int n, m, k;
  6. int d[N], backup[N];
  7. struct Edge
  8. {
  9.     int a, b, w;
  10. }edges[M];
  11. void bellman_ford()
  12. {
  13.     memset(d, 0x3f, sizeof d);
  14.     d[1] = 0;
  15.     for (int i = 0; i < k; i++)
  16.     {
  17.         memcpy(backup, d, sizeof d);
  18.         for (int j = 0; j < m; j++)
  19.         {
  20.             auto e = edges[j];
  21.             d[e.b] = min(d[e.b], backup[e.a] + e.w);
  22.         }
  23.     }
  24. }
  25. int main()
  26. {
  27.     cin >> n >> m >> k;
  28.     for (int i = 0; i < m; i++)
  29.     {
  30.         int a, b, w;
  31.         scanf("%d%d%d", &a, &b, &w);
  32.         edges[i] = {a, b, w};
  33.     }
  34.     bellman_ford();
  35.     if (d[n] > 0x3f3f3f3f / 2) cout << "impossible" << endl;
  36.     else cout << d[n] << endl;
  37.     return 0;
  38. }
复制代码
2.4、SPFA求最短路


代码模板:
  1. #include <iostream>
  2. #include <cstring>
  3. #include <queue>
  4. using namespace std;
  5. const int N = 1e5+10;
  6. int n, m;
  7. int h[N], e[N], w[N], ne[N], idx;
  8. int d[N];
  9. bool st[N];
  10. void add(int a, int b, int c)
  11. {
  12.     e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
  13. }
  14. void spfa()
  15. {
  16.     memset(d, 0x3f, sizeof d);
  17.     d[1] = 0;
  18.     queue<int> q;
  19.     q.push(1);
  20.     st[1] = true;
  21.     while (q.size())
  22.     {
  23.         auto t = q.front();
  24.         q.pop();
  25.         st[t] = false;
  26.         for (int i = h[t]; i != -1; i = ne[i])
  27.         {
  28.             int j = e[i];
  29.             if (d[j] > d[t] + w[i])
  30.             {
  31.                 d[j] = d[t] + w[i];
  32.                 if (!st[j])
  33.                 {
  34.                     st[j] = true;
  35.                     q.push(j);
  36.                 }
  37.             }
  38.         }
  39.     }
  40. }
  41. int main()
  42. {
  43.     cin >> n >> m;
  44.     memset(h, -1, sizeof h);
  45.     while (m--)
  46.     {
  47.         int a, b, c;
  48.         scanf("%d%d%d", &a, &b, &c);
  49.         add(a, b, c);
  50.     }
  51.     spfa();
  52.     if (d[n] == 0x3f3f3f3f) cout << "impossible" << endl;
  53.     else cout << d[n] << endl;
  54.     return 0;
  55. }
复制代码
2.5、SPFA判负环


  1. #include <iostream>
  2. #include <cstring>
  3. #include <queue>
  4. using namespace std;
  5. const int N = 2010, M = 10010;
  6. int h[N], e[M], w[M], ne[M], idx;
  7. int n, m;
  8. int d[N], cnt[N];
  9. bool st[N];
  10. void add(int a, int b, int c)
  11. {
  12.     e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
  13. }
  14. bool spfa()
  15. {
  16.     queue<int> q;
  17.     for (int i = 1; i <= n; i++)
  18.     {
  19.         q.push(i);
  20.         st[i] = true;
  21.     }
  22.     while (q.size())
  23.     {
  24.         auto t = q.front();
  25.         q.pop();
  26.         st[t] = false;
  27.         for (int i = h[t]; i != -1; i = ne[i])
  28.         {
  29.             int j = e[i];
  30.             if (d[j] > d[t] + w[i])
  31.             {
  32.                 d[j] = d[t] + w[i];
  33.                 cnt[j] = cnt[t] + 1;
  34.                 if (cnt[j] >= n) return true;
  35.                 if (!st[j])
  36.                 {
  37.                     st[j] = true;
  38.                     q.push(j);
  39.                 }
  40.             }
  41.         }
  42.     }
  43.     return false;
  44. }
  45. int main()
  46. {
  47.     cin >> n >> m;
  48.     memset(h, -1, sizeof h);
  49.     while (m--)
  50.     {
  51.         int a, b, c;
  52.         scanf("%d%d%d", &a, &b, &c);
  53.         add(a, b, c);
  54.     }
  55.     if (spfa()) cout << "Yes" << endl;
  56.     else cout << "No" << endl;
  57.     return 0;
  58. }
复制代码
2.6、Floyd算法


  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. const int N = 210, INF = 0x3f3f3f3f;
  5. int d[N][N];
  6. int n, m, k;
  7. void floyd()
  8. {
  9.     for (int k = 1; k <= n; k++)
  10.         for (int i = 1; i <= n; i++)
  11.             for (int j = 1; j <= n; j++)
  12.                 d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
  13. }
  14. int main()
  15. {
  16.     cin >> n >> m >> k;
  17.     for (int i = 1; i <= n; i++)
  18.         for (int j = 1; j <= n; j++)
  19.             if (i == j) d[i][j] = 0;
  20.             else d[i][j] = INF;
  21.     while (m--)
  22.     {
  23.         int a, b, c;
  24.         cin >> a >> b >> c;
  25.         d[a][b] = min(d[a][b], c);
  26.     }
  27.     floyd();
  28.     while (k--)
  29.     {
  30.         int l, r;
  31.         cin >> l >> r;
  32.         if (d[l][r] > INF / 2) cout << "impossible" << endl;
  33.         else cout << d[l][r] << endl;
  34.     }
  35.     return 0;
  36. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

瑞星

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表