图论-最短路径-Dijkstra
单源、无负权(会出现负值圈)可打印路径的模版:O(n^2)
Dijkstra求解是一个点一旦已经访问了,后续即使有从起点到该点更短的路径,也无法更新了。所以不适合有负权的图。如下图:1->2的最短路径应该是1->3->2,而不是1->2。实质:贪心
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = 10000;
- const int inf = 1e9;
- int n, G[maxn][maxn], m;//n个点,m条边
- int dis[maxn], path[maxn];
- bool vis[maxn]={false};
- void Dijkstra(int s)
- {
- for(int i = 0; i < n; i++)
- {
- dis[i] = G[s][i];
- if(G[s][i] != inf) path[i] = s;
- else path[i] = -1;
- }
- dis[s] = 0;//起点距离自身为0
- for(int i = 0; i < n; i++)//循环n次,或者令vis[s]=1,循环n-1次
- {
- int u = -1, minn = inf;
- for(int j = 0; j < n; j++)
- {
- if(!vis[j] && dis[j] < minn)
- {
- u = j;
- minn = dis[j];//找未访问过的最短的距离
- }
- }
- if(u == -1) break;//不连通
- vis[u] = true;
- for(int v = 0; v < n; v++)
- {
- //从该点出发更新其他点到起点的距离
- if(!vis[v] && dis[u] + G[u][v] < dis[v])
- {
- dis[v] = dis[u] + G[u][v];
- path[v] = u;//可输出路径
- }
- }
- }
- }
- void displayPath(int e)
- {
- vector<int> p;
- printf("0-->%d 距离:%d\n路径为:",e, dis[e]);
- p.push_back(e);
- int pre = path[e];
- while(pre != -1)
- {
- p.push_back(pre);
- pre = path[pre];
- }
- for(int i = p.size() - 1; i >0; i--)
- printf("%d-->", p[i]);
- printf("%d\n", p[0]);
- }
- int main()
- {
- freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
- ios::sync_with_stdio(false);
- cin.tie(nullptr);
- cout.tie(nullptr);
- cin >> n >> m;
- int x, y, z;
- fill(G[0],G[0]+maxn*maxn,inf);//全都初始化不可达到
- for(int i = 0; i < m; i++)
- {
- cin >> x >> y >> z;
- G[x][y] = G[y][x] = z;
- }
- Dijkstra(0);
- for(int i = 0; i < n; i++)
- displayPath(i);
- return 0;
- }
图论-最短路径-Floyd
多源,无环,无负权:O(n^3) 实质:动态规划
再考虑顶点2和3,更新距离和路径
路径的求解原理:
路径的求解:
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = 10000;
- const int inf = 1e9;
- int n,m;
- int dis[maxn][maxn], path[maxn][maxn], edges[maxn][maxn];
- void Floyd()
- {
- for(int i = 0; i < n; i++)
- {
- for(int j = 0; j < n; j++)
- {
- if(i == j) dis[i][j] = 0;//i==j需要特殊处理一下
- else dis[i][j] = edges[i][j];
- //注意i != j,因为是多源,不能像Dijkstra那样把起点的path设成-1
- if(i != j && dis[i][j] != inf) path[i][j] = i;
- else path[i][j] = -1;
- }
- }
- for(int k = 0; k < n; k++)
- {
- for(int i = 0; i < n; i++)
- {
- for(int j = 0; j < n; j++)
- {
- if(dis[i][k] + dis[k][j] < dis[i][j])
- {
- dis[i][j] = dis[i][k] + dis[k][j];
- path[i][j] = path[k][j];
- }
- }
- }
- }
- }
- int main()
- {
- //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
- ios::sync_with_stdio(false);
- cin.tie(nullptr);
- cout.tie(nullptr);
- cin >> n >> m;
- int x, y, z;
- fill(edges[0],edges[0]+maxn*maxn,inf);//全都初始化不可达到
- for(int i = 0; i < m; i++)
- {
- cin >> x >> y >> z;
- edges[x][y] = edges[y][x] = z;
- }
- Floyd();
- for(int i = 0; i < n; i++)
- printf("dis[0][%d]: %d\n", i, dis[0][i]);
- return 0;
- }
图论-最短路径-SPFA(队列优化的Bellman-Ford)
不适合负权回路的图,单源最短路:O(e)-O(ne) e为边数
- #include <bits/stdc++.h>
- using namespace std;
- const int maxn = 10000;
- const int inf = 1e9;
- int n,m;
- int dis[maxn], path[maxn], vis[maxn];
- struct node{
- int Next,val;
- };
- vector<node> edges[maxn];
- queue<int> q;
- void spfa(int s)
- {
- for(int i = 0; i < n; i++)
- {
- dis[i] = inf;
- path[i] = -1;
- }
- dis[s] = 0;//自己到自己0
- vis[s] = 1;
- q.push(s);
- while(!q.empty())
- {
- int u = q.front();
- q.pop();
- vis[u] = 0;
- for(int i = 0; i < edges[u].size(); i++)//松弛和自己相邻的边
- {
- int v = edges[u][i].Next, weight = edges[u][i].val;
- if(dis[u] + weight < dis[v])
- {
- dis[v] = dis[u] + weight;
- path[v] = u;
- if(!vis[v])
- {
- vis[v] = 1;
- q.push(v);
- }
- }
- }
- }
- }
- int main()
- {
- //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
- ios::sync_with_stdio(false);
- cin.tie(nullptr);
- cout.tie(nullptr);
- cin >> n >> m;
- int x, y, z;
- for(int i = 0; i < m; i++)
- {
- cin >> x >> y >> z;
- edges[x].push_back({y,z});
- edges[y].push_back({x,z});
- }
- spfa(0);
- for(int i = 0; i < n; i++)
- printf("dis[%d]:%d\n",i, dis[i]);
- return 0;
- }