Dijkstra算法
Dijkstra适用于边权值均为非负的图。
以下代码处理从A到G的最短路径
A B 5
A D 2
A E 7
B D 3
D E 1
B C 1
E C 9
E F 4
E G 3
F G 1
算法主要用到两个数组,一个dis[999]存储最短路径,一个check[999]存储每个节点是否更新
1,算法首先初始化dis,每个节点初始化无穷大,起点设置为0
2,然后找出dis中最近的节点Point A(第一次找到的是起点)
3,然后遍历图中可到达的节点Point B,判断dis[B]是否大于dis[A] + A到B的距离,然后更新dis
4,更新完后该节点已经使用完毕,就将他加入check数组中
循环2,3,4直到全部check之后,dis中的就是A到达所有节点的最短距离
#include <bits/stdc++.h>
using namespace std;
string begin = "A";
string end = "G";
map<string,int> dis;
set<string> check;
void Dijkstra(map<string,map<string,int>> m)
{
//初始化dis
for(auto elem : m) dis.insert({elem.first,99999});
dis[::begin] = 0;
while(check.size() != m.size())
{
//选择dis中最近的节点
string min_s;
int min_i = 99999;
for(auto elem : dis)
{
if(check.find(elem.first) == check.end() && elem.second < min_i)
{
min_i = elem.second;
min_s = elem.first;
}
}
//循环更新最短路径
for(auto elem : m[min_s])
{
if(dis[elem.first] > dis[min_s] + m[min_s][elem.first])
{
dis[elem.first] = dis[min_s] + m[min_s][elem.first];
}
}
check.insert(min_s);
}
}
int main()
{
map<string,map<string,int>> m;
for(int i = 0;i < 10;++i)
{
string x,y;
int num;
cin >> x >> y >> num;
m[x].insert({y,num});
m[y].insert({x,num});
}
Dijkstra(m);
return 0;
}
Floyd算法
十分简单的一个算法
//循环处理
for(int i = 0;i < date.size();++i)
{
for(int j = 0;j < date.size();++j)
{
for(int k = 0;k < date.size();++k)
{
if(grap[j][k] > grap[j][i] + grap[i][k])
{
grap[j][k] = grap[j][i] + grap[i][k];
}
}
}
}
//去除自最短路径
for(int i = 0;i < date.size();++i) grap[i][i] = 0;
原理也十分简单:从a到b和a到c加上c到b一样,可以通过这一点,将c用所有节点代替,然后每次循环判断整个图,循环中更新,最后将所有自最短路径改为0即可
因为我一直用的邻接表,所以有一个建立邻接矩阵的过程
#include <bits/stdc++.h>
using namespace std;
void Floyd(map<string,map<string,int>> m)
{
//建立邻接矩阵
map<string,int> date;
int temp = 0;
for(auto elem : m) date.insert({elem.first,temp++});
int grap[date.size()][date.size()];
for(int i = 0;i < date.size();++i)
{
for(int j = 0;j < date.size();++j)
{
grap[i][j] = 9999999;
}
}
for(auto elem1 : m)
{
for(auto elem2 : elem1.second)
{
grap[date[elem1.first]][date[elem2.first]] = elem2.second;
grap[date[elem2.first]][date[elem1.first]] = elem2.second;
}
}
//循环处理
for(int i = 0;i < date.size();++i)
{
for(int j = 0;j < date.size();++j)
{
for(int k = 0;k < date.size();++k)
{
if(grap[j][k] > grap[j][i] + grap[i][k])
{
grap[j][k] = grap[j][i] + grap[i][k];
}
}
}
}
//去除自最短路径
for(int i = 0;i < date.size();++i) grap[i][i] = 0;
return;
}
int main()
{
map<string,map<string,int>> m;
for(int i = 0;i < 10;++i)
{
string x,y;
int num;
cin >> x >> y >> num;
m[x].insert({y,num});
m[y].insert({x,num});
}
Floyd(m);
return 0;
}
Bellman算法
使用松弛的方法来选择最短路径
使用l[],r[],v[],dis[]四个数组,但是比floyd更简单
松弛代码为:
for(int i = 1;i <= n;++i)
{
if(dis[l[i]] > dis[r[i]] + v[i]) dis[l[i]] = dis[r[i]] + v[i];
}
然后松弛边数-1的次数即可
#include <bits/stdc++.h>
using namespace std;
void Bellman(int *dis,const int *l,const int *r,const int *v,const int n,const int m)
{
for(int k = 1;k < n;++k)
{
for(int i = 1;i <= m;++i)
{
if(dis[r[i]] > dis[l[i]] + v[i]) dis[r[i]] = dis[l[i]] + v[i];
}
}
}
int main()
{
int n,m;
cin >> n;
int dis[n+1];
fill(dis,dis + n + 1,9999);
dis[1] = 0;
cin >> m;
int left[m + 1];
int right[m + 1];
int value[m + 1];
for(int i = 1;i <= m;++i) cin >> left[i] >> right[i] >> value[i];
Bellman(dis,left,right,value,n,m);
for(int i : dis) cout << i << endl;
return 0;
}
/*
7
10
1 2 5
1 4 2
1 5 7
2 4 3
4 5 1
2 3 1
5 3 9
5 6 4
5 7 3
6 7 1
*/
队列优化的Bellman算法(SPFA算法)
思考一下,只有当前继节点松弛后,他才可能松弛,所以可以通过一个队列来优化算法,当节点松弛时将字节入队即可,当队空时就证明没有可松弛的节点了。
1,将起始节点入队
2,每次去头节点,松弛头节点的所有可到达节点,如果有一个节点松弛成功,且不在队中就入队
3,重复2直到队空
结束后即为结果
展示代码在下方
SPFA算法
SPFA可以用于处理带负权的图
SPFA算法根BFS的队列相似
用到两个数组,一个dis[999]存储最短路径,一个check[999]存储点是否在队列中
1,初始化dis,起始点设置为0,其他为无穷大,将起始点入队
2,更新头节点可到达节点的距离,如果成功更新则入队(如果已经在队中则不入)
3,头节点出队
4,循环2,3直到队为空
#include <bits/stdc++.h>
using namespace std;
string begin = "A";
map<string,int> dis;
set<string> check;
void SPFA(map<string,map<string,int>> m)
{
for(auto elem : m) dis[elem.first] = 999999;
deque<string> d;
d.push_back(::begin);
dis[::begin] = 0;
check.insert(::begin);
while(!d.empty())
{
string s = d.front();
d.pop_front();
check.erase(s);
for(auto elem : m[s])
{
if(dis[s] + m[s][elem.first] < dis[elem.first])
{
dis[elem.first] = dis[s] + m[s][elem.first];
if(check.find(elem.first) == check.end()) d.push_back(elem.first);
}
}
}
}
int main()
{
map<string,map<string,int>> m;
for(int i = 0;i < 10;++i)
{
string x,y;
int num;
cin >> x >> y >> num;
m[x].insert({y,num});
m[y].insert({x,num});
}
SPFA(m);
return 0;
}