最短路算法还有spfa算法,但是对于比赛的一些数据来说,单纯的求最短路还是用D算法更快更稳定,但是对于有负权值的边来说,就必须用到spfa算法了,所以放在下次说。
floyd 5 行算法,求各个点之间的最短路,相当于遍历每个边,做传递,a-c,c-b,那么a就可以通过c到b。时间复杂度O(n^3)
ps:一般就这种用邻接矩阵存好点
模板代码:
void read(){
memset(g,0x3f,sizeof d);
scanf("%d%d",&n,&m);
for(int i=1;i <= n;i++) d[i][i] = 0;
for(int i = 1;i <= m;i ++){
int x,y,w;scanf("%d%d%d",&x,&y,&w);
d[x][y] = d[y][x] = w;
}
//memcpy(dis,g,sizeof g);
}
void floyd(){
for(int k=1;k<=n;k++)//这里要先枚举k(可以理解为中转点)
for(int i=1;i<=n;i++){
if(i==k || d[i][k]==inf) continue; //剪枝
for(int j=1;j<=n;j++)
d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
//松弛操作,即更新每两个点之间的距离
//松弛操作有三角形的三边关系推出
//即两边之和大于第三边
}
}
dijkstra算法:
Dijkstra是基于一种贪心的策略,首先用数组dis记录起点到每个结点的最短路径,再用一个数组保存已经找到最短路径的点
然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点记为已经找到最短路
此时完成一个顶点,再看这个点能否到达其它点(记为v),将dis[v]的值进行更新
不断重复上述动作,将所有的点都更新到最短路径
这种算法实际上是O(n^2)的时间复杂度,但我们发现在dis数组中选择最小值时,我们可以用一些数据结构来进行优化。
其实我们可以用STL里的堆来进行优化,堆相对于线段树以及平衡树有着常数小,码量小等优点,并且堆的一个巧妙的性质就是可以在nlogn的时限内满足堆顶是堆内元素的最大(小)值。
//送一个路径保存
#include
using namespace std;
const int N = 500010;
const int INF = 2147483647;
typedef pair P;
#define MP make_pair
#define F first
#define S second
int n,m,s,cnt;
int ver[N],nex[N],edge[N];
int head[N],vis[N],dis[N];
priority_queue q;
void add(int a,int b,int w){
ver[++cnt] = b;
edge[cnt] = w;
nex[cnt] = head[a];
head[a] = cnt;
}
void init(){
scanf("%d %d %d",&n,&m,&s);
memset(head,-1,sizeof head);
for(int i=1,a,b,w;i<=m;i++){
scanf(" %d %d %d",&a,&b,&w);
add(a,b,w);
}
}
int path[N];
void djstl(){
for(int i=0;i<=n;i++)
vis[i] = 0,dis[i] = INF;
q.push(MP(0,s)),dis[s] = 0;
while(q.size()){
int u = q.top().S; q.pop();
/*int u = q.top().S,uw=q.top().F; q.pop();
if(dis[u]!=-uw) continue;*/
if(vis[u]) continue;
vis[u] = 1;
for(int i=head[u];~i;i = nex[i]){
int v = ver[i],w = edge[i];
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push(MP(-dis[v],v));
path[v] = u;
}
}
}
}
void getpath(int s,int t){
printf("%d-->%d: %d",s,t,s);
stack st;
while(path[t]){
st.push(t);
t = path[t];
}
while(st.size()){
printf("->%d",st.top());
st.pop();
}
printf("\n");
}
int main(){
init();
djstl();
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
printf("\n");
for(int i=2;i<=n;i++)
getpath(1,i);
return 0;
}
#include
using namespace std;
const int N = 500010;
const int INF = 2147483647;
typedef pair P;
#define MP make_pair
#define F first
#define S second
int n,m,s,cnt;
int ver[N],nex[N],edge[N];
int head[N],vis[N],dis[N];
priority_queue q;
void add(int a,int b,int w){
ver[++cnt] = b;
edge[cnt] = w;
nex[cnt] = head[a];
head[a] = cnt;
}
void init(){
scanf("%d %d %d",&n,&m,&s);
memset(head,-1,sizeof head);
for(int i=1,a,b,w;i<=m;i++){
scanf(" %d %d %d",&a,&b,&w);
add(a,b,w);
}
}
void djstl(){
for(int i=0;i<=n;i++)
vis[i] = 0,dis[i] = INF;
q.push(MP(0,s)),dis[s] = 0;
while(q.size()){
int u = q.top().S; q.pop();
/*int u = q.top().S,uw=q.top().F; q.pop();
if(dis[u]!=-uw) continue;*/
if(vis[u]) continue;
vis[u] = 1;
for(int i=head[u];~i;i = nex[i]){
int v = ver[i],w = edge[i];
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push(MP(-dis[v],v));
}
}
}
}
int main(){
init();
djstl();
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
SPFA 算法
void spfa(){
queue q;
for(int i = 0;i <= n;i++) dis[i] = INF;
q.push(s),dis[s] = 0,vis[s] = 1;
while(q.size()){
int u = q.front(); q.pop();vis[u] = 0;
for(int i=head[u];i;i = nex[i]){
int v = ver[i],w=edge[i];
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
if(!vis[v]){
q.push(v),vis[v] = 1;
}
}
}
}
}