这道题是模板题,有很多种做法。我使用Bellman-Fordspfa、floyd算法来做练习,积累些经验。

难点:

1.无穷会因为负权边松弛,即INF+w<INF .

例如:设dis为到点1的最短路的长度,dis[2]=INF,dis[3]=INF,存在边(2,3)=-2,除此之外没有以3为终点的边

则根据dis[v]>dis[u]+w,dis[3]=INF-2!=INF,这将导致dis[3]理论上结果为无穷,但是实际数值不为INF的情况。

为避免这种松弛导致判断不可达该点时, dis[i]!=INF但i点实际不可达的情况,采取特判dis[u]不为无穷,避免松弛。

         int u=edges[i].u,v=edges[i].v,w=edges[i].w;if(dis[u]!=INF&&dis[v]>dis[u]+w)/*无穷会因为负权边松弛,即INF+w<INF .为避免这种松弛导致判断不可达该点时,dis[i]!=INF但i点实际不可达的情况,采取特判dis[u]不为无穷,避免松弛。 */{dis[v]=dis[u]+w;}

2.若不能到达则输出 231-1。这个数据在Int范围内,但是表示时需要注意移位运算与减法运算的优先级

long long INF=(1<<31)-1;//减法优先级高于移位,需要加括号提高优先级

整体代码如下,没有考虑优化,三个TLE。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=5e5+10, INF=(1<<31)-1;//减法优先级高于移位,需要加括号提高优先级
int idx;
long long dis[N];
struct edge{int u,v,w;//出边、权值、下一出边
};
edge edges[M];
int n,m,u,v,w;
void add(int u,int v,int w){edges[idx].u=u;edges[idx].v=v;edges[idx].w=w;idx++;
}
void BF(){for(int i=0;i<n-1;i++)//传递n-1次,避免负环 {for(int i=0;i<m;i++){int u=edges[i].u,v=edges[i].v,w=edges[i].w;if(dis[u]!=INF&&dis[v]>dis[u]+w)/*无穷会因为负权边松弛,即INF+w<INF .为避免这种松弛导致判断不可达该点时,dis[i]!=INF但i点实际不可达的情况,采取特判dis[u]不为无穷,避免松弛。 */{dis[v]=dis[u]+w;}}}
}
int main(){int s;cin>>n>>m>>s;for(int i=0;i<m;i++){//录入边, cin>>u>>v>>w;add(u,v,w);}for(int i=1;i<=n;i++)dis[i]=INF;//该无穷大无法用类似0x3f赋值 dis[s]=0;//源点最短路初始化 BF();for(int i=1;i<n;i++)cout<<dis[i]<<' ';cout<<dis[n]<<endl;return 0;
}

优化

某轮未发生松弛,则接下来的传递必然不会发生松弛。

方案:采用对每轮标记是否发生松弛,来判定结束时机。结束时机要么是所有轮迭代完,要么是某轮未发生松弛

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=5e5+10, INF=(1<<31)-1;//减法优先级高于移位,需要加括号提高优先级
int idx;
long long dis[N];
struct edge{int u,v,w;//出边、权值、下一出边
};
edge edges[M];
int n,m,u,v,w;
void add(int u,int v,int w){edges[idx].u=u;edges[idx].v=v;edges[idx].w=w;idx++;
}
void BF(){for(int i=0;i<n-1;i++)//传递n-1次,避免负环 {    int check=0; //每轮都需要初始标记 for(int i=0;i<m;i++){int u=edges[i].u,v=edges[i].v,w=edges[i].w;if(dis[u]!=INF&&dis[v]>dis[u]+w)/*无穷会因为负权边松弛,即INF+w<INF .为避免这种松弛导致判断不可达该点时,dis[i]!=INF但i点实际不可达的情况,采取特判dis[u]不为无穷,避免松弛。 */{dis[v]=dis[u]+w;check=1;//松弛则标记该轮传递有 }}if(!check)break;//某次传递所有点都没有松弛,则说明所有可能的松弛已经结束。 }
}
int main(){int s;cin>>n>>m>>s;for(int i=0;i<m;i++){//录入边, cin>>u>>v>>w;add(u,v,w);}for(int i=1;i<=n;i++)dis[i]=INF;//该无穷大无法用类似0x3f赋值 dis[s]=0;//源点最短路初始化 BF();for(int i=1;i<n;i++)cout<<dis[i]<<' ';cout<<dis[n]<<endl;return 0;
}

spfa是上面算法的队列优化版本

思想:被松弛的终点v可以作为下一次传递的起点u,来尝试下一次传递。

由于松弛后v的最短路路长被修改,那么它的所有出度结点的最短路都会受到影响。好比一波激起千层浪。

故而通过将被松弛节点v入队列的方式维护它的出度,维护完毕后则该节点v出队。如果被松弛的终点v在队列中,显然它正等待维护它的出度。由于终点被松弛后会影响它的出度,但只会因为两点关联的边而发生可能的松弛,由关联的定义得维护出度只需要一次传递即可,因此被松弛且队列的终点v不需要再次入队,否则就是浪费时间。

显然是一种贪心策略:通过确定当前结点v的最短路路长,来维护v的所有出度的最短路。

代码如下

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=5e5+10;
const long long INF=(1<<31)-1;
int n,m,s;
long long dis[N];
int vis[N],idx,h[N],ne[M],e[M],to[M];
void add(int u,int v,int w){ne[idx]=h[u];to[idx]=v;e[idx]=w;h[u]=idx++;
}
void spfa(){for(int i=1;i<=n;i++)dis[i]=INF;dis[s]=0;queue<int> q;q.push(s);while(!q.empty()){int t=q.front();q.pop();vis[t]=0;for(int i=h[t];~i;i=ne[i]){int v=to[i],w=e[i];if(dis[t]!=INF&&dis[v]>dis[t]+w){dis[v]=dis[t]+w;if(!vis[v]){//被松弛且未在队列q中的汇点入队 vis[v]=1;q.push(v);}} }}
}
int main(){freopen("test.txt","r",stdin);cin>>n>>m>>s;memset(h,-1,sizeof h);for(int i=0;i<m;i++){int a,b,c;cin>>a>>b>>c;add(a,b,c);}spfa();for(int i=1;i<n;i++)cout<<dis[i]<<' ';cout<<dis[n]<<endl;return 0;
}

floyd算法

采用floyd求解会超时。

而且本题的重边会导致邻接矩阵算法WA。重边的应对方案是记录其中权值最小的边。

for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;if(maze[u][v]>w)//应对本题的重边 maze[u][v]=w;}

本题仍需要松弛,因此需要判断松弛对象是否为INF,避免松弛无路顶点的情况

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,INF=(1<<31)-1;
int maze[N][N];
int n,m,s;
void floyd(){for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){if(maze[k][j]!=INF&&maze[i][k]!=INF&&maze[i][j]>maze[i][k]+maze[k][j]){maze[i][j]=maze[i][k]+maze[k][j];}}
}
int main(){freopen("test.txt","r",stdin);cin>>n>>m>>s;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=j)maze[i][j]=INF;else maze[i][j]=0;for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;if(maze[u][v]>w)//应对本题的重边 maze[u][v]=w;}floyd();for(int i=1;i<n;i++){cout<<maze[s][i]<<' ';}cout<<maze[s][n]<<endl;return 0;
}

[P3371 ]【模板】单源最短路径相关推荐

  1. P3371 【模板】单源最短路径(弱化版)

    题目 P3371 [模板]单源最短路径(弱化版) 分析 Dijkstra模板题,只不过这里用了链式前向星 AC代码 #include<cstdio> #include<iostrea ...

  2. 洛谷 P3371 【模板】单源最短路径(弱化版)【最短路】【spfa】

    洛谷 P3371 [模板]单源最短路径(弱化版) 一.题目链接 二.题目分析 (一)算法标签 (二)解题思路 三.AC代码 四.其它题解 一.题目链接 洛谷 P3371 [模板]单源最短路径(弱化版) ...

  3. p3371 单源最短路径(弱化版)-java题解-最短路

    弱化版传送门: P3371 [模板]单源最短路径(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目背景 本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通 ...

  4. P4779 【模板】单源最短路径(标准版)

    # [模板]单源最短路径(标准版) ## 题目背景 2018 年 7 月 19 日,某位同学在 [NOI Day 1 T1 归程](https://www.luogu.org/problemnew/s ...

  5. Luogu 3371【模板】单源最短路径

    Luogu 3371[模板]单源最短路径 第一次写博客用图论题来试一试 接下来是正文部分 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包 ...

  6. 最短路——【模板】单源最短路径(弱化版)(dijkstra)

    题目链接 最短路--[模板]单源最短路径(弱化版)(dijkstra) 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入格式 第一行包含三个整数 n,m,s,分别表示点 ...

  7. 洛谷_P3371 【模板】单源最短路径(弱化版)_dijkstra_堆优化

    洛谷_P3371 [模板]单源最短路径(弱化版)_dijkstra_堆优化 // dijkstra最短路算法_堆优化 #include<bits/stdc++.h> using names ...

  8. 单源最短路径(最短路)

    洛谷--P3371 [模板]单源最短路径(spfa) 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个 ...

  9. Dijkstra算法求解单源最短路径问题

    文章目录 一 前言 二 Dijkstra 算法讲解 1. 贪心算法的证明 2. 算法实现说明 3. 初版Dijkstra算法代码 三 时间复杂度优化 1. 优化策略 2. 优化后的代码 四 结语 一 ...

  10. p4779 单源最短路径(标准版)-java版

    传送门: P4779 [模板]单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P4779 先给 ...

最新文章

  1. 高压放电与防静电塑料包装
  2. 编译有哪些阶段,动态链接和静态链接的区别 c++
  3. 如何让 Mybatis 自动生成代码
  4. graphpad如何检测方差齐_如何选择方差分析中“多重比较”的方法?
  5. 用CSS3来代替JS实现交互
  6. 华为Mate 40 Pro维修价来了:这个部件最贵,够买一部顶级旗舰
  7. 对Gson解析的理解
  8. (16)数据结构-并查集
  9. C语言项目源码2022必看必学版
  10. 分布式面试题(二):分布式Redis
  11. 高频分类ISO1443, ISO15693, ISO18000-3
  12. 类似print shopmail可变数据生成,排版、拼版实现
  13. 个人朋友圈时代过去了,企业微信朋友圈开辟营销新思路
  14. java speex转码_JAVA版-微信语音.speex转.wav
  15. LeetCode——5776. 判断矩阵经轮转后是否一致(Determine Whether Matrix Can Be Obtained By Rotation)[简单]——分析及代码(Java)
  16. 用c语言编程一个英尺转换器,C语言中关于英尺、英寸、厘米的换算
  17. 移动端电影院社交来啦 约上ta看一场电影
  18. 如何从Google Play下载应用到电脑
  19. java method field_java_解析Java中的Field类和Method类,Field类 Field类中定义了一些方 - phpStudy...
  20. 126邮箱OUTLOOKS设置

热门文章

  1. MotionLayout MotionScene 动画从未如此简单!
  2. 如何在Release状态下进行调试
  3. Java中有序与无序
  4. 《Linux那些事儿之我是USB》我是U盘(7)狂欢是一群人的孤单
  5. Android之WiFi连接检测
  6. c++实现“反应时间”测试
  7. 安科瑞数据中心行业电能质量监测与治理方案-李亚俊
  8. Debian 国内常用镜像源
  9. 编解码base64、对称加密aes和非对称加密rsa
  10. 通过替换音效文件,实现在安卓手机上使用wp/nokia/wm10按键键盘声音