最短路
1.Floyd_Warshall算法
核心思路:d[i][j] = min{d[i][j], d[i][k] + d[k][j]}
从i到j有两种路径,经过k点或是不经过k点,所以我们枚举k即可求所有路的最短路。
适用范围:求任意两点间的最短路,可以有负权,可以是有向图可以是无向图,但是n必须在200以内
1 #include <iostream> 2 #include <stdio.h> 3 #include <string> 4 #include <string.h> 5 #include <queue> 6 #include <vector> 7 #define INF 0x3f3f3f3f 8 9 using namespace std; 10 11 int main() 12 { 13 int n, m, s, t; 14 while(~scanf("%d%d", &n, &m)) 15 { 16 vector<vector<int> > dis(n);//vector二维可变长数组 17 for(int i = 0; i < n; i++) 18 { 19 dis[i].resize(n, INF);//初始化设置dis[i]的长度,并用INF作为初始值 20 dis[i][i] = 0; 21 } 22 for(int i = 0; i < m; i++)//输入边a,b两点的权值是x 23 { 24 int a, b, x; 25 scanf("%d%d%d", &a, &b, &x); 26 if(dis[a][b] > x) 27 dis[a][b] = dis[b][a] = x; 28 } 29 scanf("%d%d", &s, &t); 30 for(int k = 0; k < n; k++) 31 for(int i = 0; i < n; i++) 32 for(int j = 0; j < n; j++) 33 { 34 if(dis[i][k] < INF && dis[k][j] < INF) 35 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); 36 } 37 if(dis[s][t] != INF)//可以求任意两点间最短路 38 printf("%d\n", dis[s][t]); 39 else 40 printf("-1\n"); 41 } 42 return 0; 43 }
2.Dijkstra算法
核心思路:
D(s, t) = {Vs … Vi … Vj … Vt}表示s到t的最短路,其中i和j是这条路径上的两个中间结点,那么D(i, j)必定是i到j的最短路,如果存在这样一条最短路D(s, t) = {Vs … Vi Vt},其中i和t是最短路上相邻的点,那么D(s, i) = {Vs … Vi} 必定是s到i的最短路。Dijkstra算法就是基于这样一个性质,通过最短路径长度递增,逐渐生成最短路。
适用情况:
正权图上的单元最短路,有向图无向图,从单个源点出发到所有结点的最短路
1 #include <iostream> 2 #include <stdio.h> 3 #include <string> 4 #include <string.h> 5 #include <queue> 6 #include <vector> 7 #define INF 0x3f3f3f3f 8 9 using namespace std; 10 const int maxn = 105; 11 int dis[maxn], pre[maxn]; 12 13 struct Edge//边 14 { 15 int u, v, w; 16 Edge() {}; 17 Edge(int uu, int vv, int ww): u(uu), v(vv), w(ww) {}; 18 }; 19 20 vector<Edge> edges;//边数组 21 vector<int> G[maxn];//存储每个节点对应的边的序号 22 23 24 void init(int nn)//清理 25 { 26 for(int i = 0; i <= nn; i++) 27 G[i].clear(); 28 edges.clear(); 29 } 30 31 void AddEdge(int uu, int vv, int ww)//加边 32 { 33 edges.push_back(Edge(uu, vv, ww)); 34 int edgenum = edges.size(); 35 G[uu].push_back(edgenum - 1); 36 } 37 38 struct node//优先队列优化,dis小的先出队 39 { 40 int u, d; 41 node() {}; 42 node(int uu, int dd): u(uu), d(dd) {}; 43 friend bool operator < (node a, node b) 44 { 45 return a.d > b.d; 46 } 47 }; 48 49 void dijkstra(int s) 50 { 51 priority_queue<node> q; 52 memset(dis, INF, sizeof(dis));//dis初始化为INF 53 dis[s] = 0; 54 q.push(node(s, dis[s])); 55 while(!q.empty()) 56 { 57 node cur = q.top(); 58 q.pop(); 59 int from = cur.u; 60 if(cur.d != dis[from])//减少了vis数组,表示该节点被取出来过 61 continue; 62 for(int i = 0; i < G[from].size(); i++)//更新所有集合外点到集合的dis 63 { 64 Edge e = edges[G[from][i]]; 65 if(dis[e.v] > dis[e.u] + e.w) 66 { 67 dis[e.v] = dis[e.u] + e.w; 68 pre[e.v] = from;//存储父节点 69 q.push(node(e.v, dis[e.v]));//将有更新的dis加入到队列中 70 } 71 } 72 } 73 } 74 int main() 75 { 76 int n, m; 77 while(~scanf("%d%d", &n, &m) && n && m) 78 { 79 init(n); 80 for(int i = 0; i < m; i++) 81 { 82 int u, v, w; 83 scanf("%d%d%d", &u, &v, &w); 84 AddEdge(u, v, w); 85 AddEdge(v, u, w); 86 } 87 dijkstra(1); 88 printf("%d\n", dis[n]); 89 } 90 return 0; 91 }
邻接表队列优化:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX = 1e9 + 7; 4 const int N = 1e6+7; 5 6 struct aa{ 7 int u,d; 8 bool operator < (const aa & a) const{ 9 return d>a.d; 10 } 11 }; 12 vector<aa>arr[N]; 13 14 bool vis[N]; 15 int n,m; 16 int d[N]; 17 18 void Dij(){ 19 fill(d+1,d+n+1,MAX); 20 d[1]=0; 21 priority_queue<aa>Q; 22 Q.push({1,0}); 23 while(!Q.empty()){ 24 aa x=Q.top(); 25 Q.pop(); 26 int u=x.u; 27 if(vis[u])continue; 28 vis[u]=1; 29 for(int i=0;i<arr[u].size();i++){ 30 aa e=arr[u][i]; 31 if(d[e.u]>d[u]+e.d){ 32 d[e.u]=d[u]+e.d; 33 Q.push({e.u,d[e.u]}); 34 } 35 } 36 } 37 } 38 int main(){ 39 int x,y,w; 40 cin>>n>>m; 41 for(int i=1;i<=m;i++){ 42 scanf("%d%d%d",&x,&y,&w); 43 arr[x].push_back({y,w}); 44 } 45 Dij(); 46 if(d[n]==MAX) 47 d[n]=-1; 48 cout<<d[n]<<endl; 49 return 0; 50 }
3.SPFA算法
核心思路:
设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止
适用情况:可以正权可以有负权,有向图无向图,从单个源点出发到所有结点的最短路
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<vector> 6 7 #define inf 0x3f3f3f3f 8 9 using namespace std; 10 11 int dis[105],visit[105]; 12 int n,m; 13 14 class Node 15 { 16 public: 17 int e,v; 18 Node(int a,int b){e = a,v = b;} 19 }; 20 21 vector<Node>s[105]; 22 23 void spfa() 24 { 25 memset(dis,inf,sizeof(dis)); 26 memset(visit,0,sizeof(visit)); 27 dis[1] = 0; 28 queue<int>q; 29 q.push(1); 30 visit[1] = true; 31 while(!q.empty()){ 32 int u = q.front(); 33 q.pop(); 34 visit[u] = false; 35 int num = s[u].size(); 36 for(int i = 0;i < num; i++){ 37 if(dis[u] + s[u][i].v > dis[s[u][i].e]) 38 continue; 39 dis[s[u][i].e] = dis[u] + s[u][i].v; 40 if(!visit[s[u][i].e]){ 41 q.push(s[u][i].e); 42 visit[s[u][i].e] = true; 43 } 44 } 45 } 46 } 47 48 int main() 49 { 50 // freopen("in.txt","r",stdin); 51 while(cin>>n>>m){ 52 if(n == 0 && m == 0) 53 break; 54 for(int i = 1;i <= n; i++) 55 s[i].clear(); 56 int a,b,c; 57 for(int i = 1;i <= m; i++){ 58 cin>>a>>b>>c; 59 s[a].push_back(Node(b,c)); 60 s[b].push_back(Node(a,c));//这里无向 61 } 62 spfa(); 63 cout<<dis[n]<<endl; 64 } 65 return 0; 66 }