写在前面:
前面我们说到Dijkstra算法,每次找到离 1 号顶点最近的顶点的时间复杂度是 O(N),可以用优先队列(堆)来优化,使得这一部分的时间复杂度降低到。
代码实现:
【vector+优先队列 优化Dijkstra】
#include
#include
#include// vector
#include// priority_queue
using namespace std;
const int Maxsize=1e4+5;// 顶点数量的最大值
const int INF=0x3f3f3f3f;// 正无穷大
// 边的结构体
struct edge
{
int d,v;// d:距离;v:节点(弧头)
edge(){}
edge(int a,int b)// 初始化 d 和 v
{
d=a,v=b;
}
// 重载"<"运算符,以便更改优先队列的排序规则
// 根据"最短距离"d来进行排序
bool operator < (const edge&x)const
{
if(d==x.d)return vx.d;
}
};
vectorG[Maxsize];// 图 G
int dis[Maxsize];// 距离表
int n,m;// n:顶点个数 m:边数
int v1,v2,w;// v1->v2,weight==w
// Dijkstra算法,源点为 s
void dijkstra(int s)
{
// 初始化dis数组
for(int i=0;i<=n;i++)dis[i]=INF;
dis[s]=0;
priority_queueque;// 优先队列
que.push(edge(dis[s],s));// 将起点压入队列
// 队列非空
while(!que.empty())
{
// get the min_index
edge temp=que.top();
que.pop();
int v=temp.v;// 顶点
if(dis[v]dis[v]+e.d)
{
dis[e.v]=dis[v]+e.d;
que.push(edge(dis[e.v],e.v));
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)
{
G[i].clear();
}
while(m--)
{
scanf("%d%d%d",&v1,&v2,&w);
G[v1].push_back(edge(w,v2));
G[v2].push_back(edge(w,v1));
}
dijkstra(1);
for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
puts("");
}
【vector实现邻接表+优先队列 (假设边一开始是字符型的,这么假设是为了加点难度)】
因为顶点是字符型,所以需要用到映射map来解决。
#include
#include
#include
#include
【数组实现邻接表+优先队列】
直接放了代码,因为时间关系,就没有自己码一边,有错还望指出。
#include
#include
#include
#include
#define inf 0x7fffffff
using namespace std;
const int MAXN = 205;
int dis[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
int first[MAXN],next[MAXN];
int n,m;
int src,ed;
typedef pair pii;
void init()
{
scanf("%d%d",&n,&m);
memset(first,-1,sizeof(first));
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]];
first[u[i] ]=i;
u[i+m]=v[i],v[i+m]=u[i],w[i+m]=w[i]; //无向边,所以加一条反向边
next[i+m]=first[u[i+m] ];
first[u[i+m] ]=i+m;
}
cin>>src>>ed;
for(int i=1;i<=n;i++) dis[i]= (i==src? 0:inf);//不要把dis[i]初始化成源点到各点的直接距离,否则会有点没入队。
}
void dijkstra()
{
priority_queue,greater >que;
que.push(pii(0,src));
while(!que.empty()){
pii tmp=que.top();
que.pop();
int x = tmp.second;
if(tmp.first!=dis[x]) continue; //如果出队的这个元素,他带的dis,和当前的dis不相同,证明这个结点是被处理过的已确定了最短路,
for(int e=first[x];e!=-1;e=next[e]){ //这种数组式邻接表的遍历
if(dis[v[e]]>dis[x]+w[e]){
dis[v[e] ]=dis[x]+w[e];
que.push(pii(dis[v[e] ],v[e]));
}
}
}
}
int main()
{
// freopen("1.in","r",stdin);
int _;
scanf("%d",&_);
while(_--){
init();
dijkstra();
if(dis[ed]==inf) cout<<"-1"<
写在最后:
参考资料:
- 博客:再谈Dijkstra算法和堆优化
- 博客:Dijkstra + 优先队列 + 邻接表优化
- 博客:Dijkstra[两种邻接表+优先队列优化](代码参考)
- 博客:C++中priority_queue的简单用法(优先队列)
- 博客:priority_queue的用法(优先队列)
优先队列,在最近的学习中,用的频率挺多的,后面有时间再来仔细研究其实现原理。
图论是真的难呀,建图可以建一年……慢慢来吧!!!