专栏文章
最短路总结
算法·理论参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioztqs8
- 此快照首次捕获于
- 2025/12/03 03:50 3 个月前
- 此快照最后确认于
- 2025/12/03 03:50 3 个月前
多源最短路
Floyd:
时间复杂度:
实现方式:
三重循环枚举起点,终点,中转点,然后进行松弛操作
代码模版:
CPPvoid floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}
}
return;
}
其中,k是中转点注意:中转点k的枚举必须写在最外层!
优点:
- 代码量小,好记,考试时遇到单源最短路的题目可以用Floyd骗一点分。
缺点:
- 时间复杂度高,大概n到就会超时。
使用场景:
处理多源最短路且n较小的时候用
单源最短路
Dijkstra:
时间复杂度:
普通版:堆优化版:实现方式:
每一次操作将当前长度最短的路径更新一个点,路径上的点数增加,路径长减少,由短的路->长的路
代码模版:
普通版:
CPPint dis[500005],n,m,s;
bool vis[500005];
struct node{
int v,w;
};
vector<node>e[500005];
void dijkstra(){
for(int i=1;i<=n;i++)dis[i]=1e18;
dis[s]=0;
for(int i=1;i<=n;i++){
int minn=1e18,p;
for(int j=1;j<=n;j++){
if(vis[j]==0&&dis[j]<minn){
minn=dis[j];
p=j;
}
}
vis[p]=1;
for(int j=0;j<e[p].size();j++){
int v=e[p][j].v,w=e[p][j].w;
if(dis[v]>dis[p]+w)dis[v]=dis[p]+w;
}
}
}
堆优化版:
CPPint n,m,s,dis[100005];
bool vis[100005];
struct node{
int v,w;
bool operator < (const node &b) const
{
return b.w<w;
}
};
vector<node>e[100005];
priority_queue<node>pq;
void dijkstra(){
pq.push({s,0});
while(pq.size()){
node tt=pq.top();
pq.pop();
int u=tt.v;
if(vis[u]==1)continue;
vis[u]=1;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].v,w=e[u][i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v])pq.push({v,dis[v]});
}
}
}
}
一般情况下,我们写代码用的都是堆优化版的dijkstra。
优点:
- 速度最快,能解决大多数单源最短路的题目
缺点:
- 无法解决负边权问题
- 代码较长,容易出错
使用场景:
处理一般单源最短路
Bellman-Ford:
时间复杂度:
实现方式:
枚举顶点和每一条边
代码模版:
CPPint n,k,dis[100005];
struct node{
int u,v,w;
}e[100005];
void bellman_ford(){
for(int i=1;i<=n;i++)dis[i]=1e18;
dis[1]=0;
while(1){
bool flag=0;
for(int i=1;i<=n;i++){
int u=e[i].u,v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
flag=1;
dis[v]=dis[u]+w;
}
}
if(!flag)break;
}
}
优点:
- 好写
- 可以处理负环问题
缺点:
- 速度较慢
使用场景:
处理负环问题,或数据较小的单源最短路
SPFA:
时间复杂度:
实现方式:
跟dijkstra差不多
代码模版:
CPPconst int N=1e5+7;
int n,m,s;
struct node{
int v,w;
};
vector<node>e[N];
queue<int>p;
int dis[N];
bool vis[N];
void spfa(){
for(int i=1;i<=n;++i){
vis[i]=0;
dis[i]=1e18;
}
dis[s]=0;
p.push(s);
vis[s]=1;
while(!p.empty()){
int u=p.front();
p.pop();
vis[u]=0;
for(int i=0;i<e[u].size();++i){
int v=e[u][i].v;
int w=e[u][i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
vis[v]=1;
p.push(v);
}
}
}
}
return ;
}
优点:
- 随机数据速度快
- 可以处理负环问题
缺点:
- 非随机数据的题目,SPFA容易被卡死
使用场景:
处理负环问题,或随机数据的单源最短路
附:Bellman-Ford和求负环(以P3385 【模板】负环为例):
Bellman-Ford:
CPP#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int n,m,dis[100005],t;
struct node{
int u,v,w;
}e[100005];
bool ballman(){
for(int i=1;i<=n;i++)dis[i]=1e18;
dis[1]=0;
for(int j=1;j<n;j++){
bool flag=0;
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v,w=e[i].w;
if(dis[u]==1e18)continue;
if(dis[v]>dis[u]+w){
flag=1;
dis[v]=dis[u]+w;
}
}
if(!flag)break;
}
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v,w=e[i].w;
if(dis[u]==1e18)continue;
if(dis[v]>dis[u]+w){
return 1;
}
}return 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n>>m;
int cnt=0;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
e[++cnt]={u,v,w};
if(w>=0)e[++cnt]={v,u,w};
}
m=cnt;
if(ballman()){
cout<<"YES\n";
}else{
cout<<"NO\n";
}
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...