蒟蒻在上一篇写了Dijkstra的基本思想,现在来讲一下它的优化。首先需要用到一个叫做优先队列以及一个叫邻接表的东西(不懂的话……百度上应该有)
上篇的算法在每次循环中都要用n来找到距离原点最近的点,维护一个小根堆可以完美解决这个问题,注意:如果不用邻接表存储的话,优不优化差不多,剩下的操作就很简单了,把循环的步骤改成:
1.取堆顶作为中转点,如果是蓝点continue
2.枚举与该点相连的每条边,更新最小值
(完美)
下面贴代码
#include<bits/stdc++.h>
using namespace std;
struct dian{
int name,val;//每个点,存它的编号和距原点的距离,用来维护小根堆
};
struct edge{
int l,r,v;//每条边,左端点,右端点和边权
};
vector<edge> g[1005];
int n,m,s1,s2,dist[1005];
bool operator < (dian a, dian b) {//重载小于号,根据距离来排序,类似于sort的cmp
return a.val > b.val;
}
priority_queue<dian> cmp;//小根堆
void Dijkstra(int x)
{
bool book[1005];
memset(book,0,sizeof(book));
for(int i=1;i<=n;i++)
{
dist[i]=INT_MAX;
}
while(cmp.size()!=0)
{
dian cun;
cun=cmp.top();cmp.pop();//代替了之前的循环来取离原点最近的白点
if(book[cun.name]==1) continue;//如果是蓝点跳过
book[cun.name]=1;
for(int i=0;i<g[cun.name].size();i++)//枚举所有边,更新答案
{
dist[g[cun.name][i].r]=min(dist[g[cun.name][i].r],cun.val+g[cun.name][i].v);
dian lin;
lin.name=g[cun.name][i].r;
lin.val=dist[g[cun.name][i].r];
cmp.push(lin);//把答案扔进堆里
}
}
}
int main()
{
cin>>n>>m;
int x,y,z;
edge lin;
for(int i=0;i<m;i++)
{
cin>>x>>y>>z;
lin.l=x;
lin.r=y;
lin.v=z;
g[x].push_back(lin);//无向图所以存两次
lin.l=y;
lin.r=x;
g[y].push_back(lin);
}
cin>>s1>>s2;
dian cun;
cun.name=s1;
cun.val=0;
cmp.push(cun);
Dijkstra(s1);
dist[s1]=0;
cout<<dist[s2];
return 0;
}
比之前快了好多有木有(写的比较丑不要太在意)