【1】2020.05.21-00:36ios
1.完善dijkstra
【2】2020.05.21-11:25
1.完善dijkstra堆优化算法
在学习图论算法的时候,最短路算法就是必学算法之一
那么既然它这么重要,就更须要咱们深刻了解,熟练掌握
默认图为连通图学习
有点贪心动规的意思优化
这个问题只要你会存图人就会作
(很像动态规划对不对)spa
^RT,咱们要求出1-5的最短路径
就必须求出起点到中转点的最短路径,中转点为4
想求出1-4的最短路径,就先去求1-3的最短路径
同理求1-2
而1-2的最短路就是其链接边的权值3d
算法思路:code
定义变量(链式前向星的那堆变量就再也不重复写了):
dis[i]
:表示从起点到i的最短距离
f[i]
:记录这条边有没有被肯定过最短路
s
表示起点blog
初始化:dis[i]=∞;dis[s]=0
排序
遍历每个点队列
#include<iostream> using namespace std; #define NUM 500050 #define INF 2147483647 struct Edge{ int na,np,w; }e[NUM]; int head[NUM],dis[NUM],num,n,m,s,u,v,w,minn; bool f[NUM]; inline void add(int f,int t,int w){ e[++num].na=head[f]; e[num].np=t,e[num].w=w; head[f]=num; } int main(){ 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; dis[s]=0; //遍历每个点 for(int i=1;i<=n;i++){ //对于每个点a,找到一个dis[b]最小的顶点b minn=-1; for(int o=1;o<=n;o++) if(f[o]==0&&(dis[minn]>dis[o]||minn==-1)) minn=o; //b被肯定过最短路 f[minn]=1; //遍历全部以b为起点的边,更新它们的dis for(int o=head[minn];o!=0;o=e[o].na) if(!f[e[o].np]) dis[e[o].np]=min(dis[e[o].np],dis[minn]+e[o].w); } //算法结束,输出s到各点的最短距离 for(int i=1;i<=n;i++) cout<<dis[i]<<" "; }
咱们能够发现,对于原来的dijkstra算法,每次查找最小值时间复杂度都为O(n)
那么有什么算法能够在常数时间内求出最小值呢?
固然是(线段树)堆啦!
创建一个小根堆,便可迅速求出全部数据的最小值
那么咱们发现,对于每次扫描,会有一些数据已经肯定过最小值,再次进行扫描会浪费时间
因此咱们要使用队列来实现
最终结论:用优先队列+二元组实现
明白了这个以后,这道题对你来讲+岩浆=黑曜石
#include<cstdio> #include<queue> #include<vector> #include<algorithm> using namespace std; #define ll int #define NUM 500050 #define INF 2147483647 struct Edge{ int na,np,w; }e[NUM]; ll head[NUM],dis[NUM],num,n,m,s,u,v,w,minn,bf,i; bool f[NUM]; priority_queue<pair<ll,ll>,vector<pair<ll,ll> >,greater<pair<ll,ll> > >q; inline void add(int f,int t,int w){ e[++num].na=head[f]; e[num].np=t,e[num].w=w; head[f]=num; } inline int read() { int X=0,W=1; char c=getchar(); while (c<'0'||c>'9') { if (c=='-') W=-1; c=getchar(); } while (c>='0'&&c<='9') X=(X<<3)+(X<<1)+c-'0',c=getchar(); return X*W; } int main(){ n=read();m=read();s=read(); for(i=0;i<m;++i){ u=read();v=read();w=read(); add(u,v,w); } for(int i=1;i<=n;++i) dis[i]=INF; dis[s]=0; //以上所有为初始化 q.push(make_pair(0,s)); //将起点压进队列 while(q.size()){ //若是队列里还有元素 bf=q.top().second;q.pop(); //bf为当前次遍历的起点,保存后将这个元素弹出 if(f[bf]) continue; //搜过了就不搜了 f[bf]=1; //没搜过就标记一下 for(int i=head[bf];i;i=e[i].na){ //一样的遍历 if(dis[bf]+e[i].w<dis[e[i].np]){ //找到了更短的路径 dis[e[i].np]=dis[bf]+e[i].w; //更新 q.push(make_pair(dis[e[i].np],e[i].np)); //既然有更优解那就将这个点压进队列,用来更新其余点 } } } for(int i=1;i<=n;++i) printf("%d ",dis[i]); //out }
那么至于为何make_pair的参数是最短距离,边的终点呢?
为何不反过来存或存其余的参数呢
由于这是个自动排序的优先队列啊
由于二元组自带排序规则啊