文章目录
最短路径问题
问题解释:
从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径
关于SPFA算法
Floyd算法
Floyd算法介绍
算法的特点:
弗洛伊德算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或无向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。
浅谈floyd算法
floyd算法的精髓在于“中转点”,例如:有个人在A点想去C点,但A到C不能直达,假设这时候有个B点,B点可以直达C点
那么我们可以先经过B点在到C点
floyd算法既是如此,假设一个二维数组为
e
[
110
]
[
110
]
,
其中一点
e
[
i
]
[
j
]
代表
i
点到
j
点的距离
e[110][110],其中一点e[i][j]代表i点到j点的距离
e[110][110],其中一点e[i][j]代表i点到j点的距离
如果
i
点不能直达
j
点,假设有一个中转点
k
,我们可以先经过
k
,然后在到
j
,那么状态转移为
[
i
]
[
k
]
+
[
k
]
[
j
]
如果i点不能直达j点,假设有一个中转点k,我们可以先经过k,然后在到j,那么状态转移为[i][k]+[k][j]
如果i点不能直达j点,假设有一个中转点k,我们可以先经过k,然后在到j,那么状态转移为[i][k]+[k][j]
接着让我们看看例题
经典例题
例题来源
思路
Floyd模板题,注意:题目给定的是无向图,我们需要统计两条边(还要注意重边,重边取最小值)
首先需要初始化,将不能到的点全部设为无穷大
接着按上面讲的状态转移方程
e
[
i
]
[
k
]
+
e
[
k
]
[
j
]
e[i][k]+e[k][j]
e[i][k]+e[k][j]与自身
e
[
i
]
[
j
]
e[i][j]
e[i][j]比较大小,取最小值即可
code
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
#define lowbit(x) ((x)&(-x))
#define ULL unsigned long long
using namespace std;
const int INF=INT_MAX;
const int N=110;
int e[N][N];
int n,m;
void Init(){//初始化
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(i==j) e[i][j]=0;
else e[i][j]=INF;
}
}
void floyd(){
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(e[i][j]>e[i][k]+e[k][j]){
e[i][j]=e[i][k]+e[k][j];//取最小值
}
}
}
void solve(){
cin >> n >> m;
Init();
for(int i=1;i<=m;++i){
int u,v,w;
cin >> u >> v >> w;
e[u][v]=e[v][u]=min(e[u][v],w);//重边取最小值
}
floyd();
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
cout << e[i][j] << " ";
}
cout << endl;
}
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
//cin >> t;
while(t--) solve();
// cout << fixed;//强制以小数形式显示
// cout << setprecision(n); //保留n位小数
return 0;
}
Dijkstra算法
Dijkstra算法介绍
算法特点:
迪杰斯特拉算法可以算出从一个顶点到其余各顶点的最短路径,解决的是有权图中最短路径问题
浅谈Dijkstra算法
迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
经典例题
例题来源
思路
Dijkstra算法的模板题,采用贪心的策略,每次遍历与起始点最近且未被访问,同时权值还是最小的点
找到这个点后,将这个点进行标记(说明起始点到该点的距离已经是最短了)
然后从该点进行拓展延伸,比较当前拓展的值与拓展之前的权值的大小,取最小值
然后继续拓展,直到拓展到终点结束
code
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int>
#define lowbit(x) ((x)&(-x))
#define ULL unsigned long long
using namespace std;
const int INF=INT_MAX;
const int mod=1e9+7;
const int N=1e4+5;
int e[N][N],dis[N],vis[N];
int n,m;
int x,y;
int flag=0;
void Init(){
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(i==j) e[i][j]=0;
else e[i][j]=INF;
}
for(int i=1;i<=n;++i){
vis[i]=0;
}
}
void dijkstra(){
for(int i=1;i<=n;++i) dis[i]=e[x][i];//从x点初始化
vis[x]=true;
for(int i=1;i<=n;++i){
int k=-1;
for(int j=1;j<=n;++j){
if(vis[j]==0 && (k==-1||dis[k]>dis[j]))//贪心策略,选最小值
k=j;
}
if(dis[k]==INF){
flag=1;
return ;
}
if(k==-1) break;
vis[k]=1;
for(int j=1;j<=n;++j){
if(vis[j]==0) dis[j]=min(dis[k]+e[k][j],dis[j]);//拓展延伸
}
}
}
void solve(){
cin >> n >> m;
Init();
for(int i=1;i<=m;++i){
int a,b,c;
cin >> a >> b >> c;
e[a][b]=min(c,e[a][b]);//去重边
}
cin >> x >> y;
flag=0;//判断是否可以到达
dijkstra();
if(flag) cout << "NO" << endl;
else cout << dis[y] << endl;
return ;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t=1;
cin >> t;
while(t--) solve();
// cout << fixed;//强制以小数形式显示
// cout << setprecision(n); //保留n位小数
return 0;
}