HZNU-ACM寒假集训Day4小结 最短路
最短路
1.Floy 复杂度O(N3) 适用于任何图(不存在负环)
模板 --kuangbin
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e3 + 50; int mp[maxn][maxn]; int n, m; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { for (int j = 1; j < m; j++) { if (i == j) mp[i][j] = 0; else mp[i][j] = INF; } } int u, v, w; for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &w); mp[u][v] = w; } for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); } } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { printf("%10d", mp[i][j]); } printf("\n"); } return 0; }
2.Dijkstra 适用于单源最短路 非负权图 堆优化 复杂度O((n+m)logm)
#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e3 + 50; struct Node { int v, c; //c为到v点的最短路长度 Node(int _v = 0,int _c=0): v(_v),c(_c) {} friend bool operator < (Node a, Node b) { return a.c > b.c; } }; struct Edge { int v, cost; Edge(int _v = 0, int _cost = 0) : v(_v), cost(_cost) {} }; vector<Edge> E[maxn]; void add_edge(int u, int v, int w) { E[u].push_back(Edge(v, w)); } int n, m; bool vis[maxn]; bool dis[maxn]; void Dijkstra(int n, int start) { memset(vis, 0, sizeof vis); for (int i = 1; i <= n; i++) dis[i] = INF; priority_queue<Node> q; while (!q.empty()) q.pop(); dis[start] = 0; q.push(Node(start, 0)); Node tmp; while (!q.empty()) { tmp = q.top(); q.pop(); int u = tmp.v; if (vis[u]) continue; vis[u] = true; for (int i = 0; i < E[u].size(); i++) { int v = E[tmp.v][i].v; int cost = E[u][i].cost; if (!vis[v] && dis[v] > dis[u] + cost) { dis[v] = dis[u] + cost; q.push(Node(v, dis[v])); } } } } int main() { scanf("%d%d", &n, &m); int u, v, w; for (int i = 0; i < m; i++) { scanf("%d%d%d", &u, &v, &w); add_edge(u, v, w); } Dijkstra(n, 1); for (int i = 1; i <= n; i++) printf("%d ", dis[i]); return 0; }
Bellman-Ford 算法
用于求解单源最短路问题的算法 可以肯定最短路径包含的边条数不会超过n-1个,或者说结点不超过n个 若超过说明形成一个环,又环权值是正的我们可以路径上将这个环删除路径长度就会变小
可用于有向图判断是否存在负环
总复杂度O(NM)
relax(u, v) { dist[v] = min(dist[v], dist[u] + edge_len(u, v)); } for (i = 1; i <= n; i++) { dist[i] = edge_len(S, i); } for (i = 1; i < n; i++) { for each edge(u, v) { relax(u, v); } }
Bellman-Ford 算法 优化 SPFA 最坏O(NM)
存在负边权时用SPFA
利用队列存储需要更新的结点,每次从队列中取出一个结点,计算是否有结点需要更新,如果有并且这个点不在队列里那么将它加入队列。
#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e3 + 50; struct Edge { int v, cost; Edge(int _v,int _cost): v(_v),cost(_cost) {} }; vector<Edge> E[maxn]; void add_edge(int u, int v, int w) { E[u].push_back(Edge(v, w)); } bool vis[maxn]; int cnt[maxn]; int dis[maxn]; bool spfa(int n, int start) { memset(vis, 0, sizeof vis); for (int i = 1; i <= n; i++) dis[i] = INF; vis[start] = true; dis[start] = 0; queue<int> q; while (!q.empty()) q.pop(); q.push(start); memset(cnt, 0, sizeof cnt); cnt[start] = 1; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = true; for (int i = 0; i < E[u].size(); i++) { int v = E[u][i].v; if (dis[v] > dis[u] + E[u][i].cost) { dis[v] = dis[u] + E[u][i].cost; if (!vis[v]) { vis[v] = true; q.push(v); if (++cnt[v]> n) return false; } } } } return true; }