dijkstra算法的堆优化
普通的dijkstra算法模板:
//数据结构 int g[LEN][LEN]; //邻接矩阵 int vis[LEN]; //标记是否访问 int dist[LEN] //源点到各点的距离 fill(dist,dist+LEN,MAX); dist[s]=0; while(1){ int u=-1,d=MAX; for(int i=0;i<N;i++){ if(!vis[i] && dist[i]<d){ d=dist[i]; u=i; } } if(u<0) break; vis[u]=1; for(int i=0;i<N;i++) if(!vis[i]){ if(dist[u]+g[u][i]<dist[i]){ dist[i]=dist[u]+g[u][i]; } } }
为了能在“取出最小的dist”这一步实现优化,我们使用priority_queue进行优化。下面用cmp结构体重载括号运算符对priority_queue进行改造:
struct cmp{ bool operator () (int a,int b){ return dist[a]>dist[b]; } }; priority_queue<int,vector<int>,cmp> pq;
然后我们来看堆优化的dijkstra算法:
//数据结构 int g[LEN][LEN]; //邻接矩阵 int vis[LEN]; //标记是否访问 int dist[LEN] //源点到各点的距离 struct cmp{ bool operator () (int a,int b){ return dist[a]>dist[b]; } }; priority_queue<int,vector<int>,cmp> pq; fill(dist,dist+LEN,MAX); dist[s]=0; pq.push(s); while(!pq.empty()){ int u=pq.top(); pq.pop(); if(vis[u]) continue; vis[u]=1; for(int i=0;i<N;i++) if(!vis[i]){ if(dist[u]+g[u][i]<dist[i]){ dist[i]=dist[u]+g[u][i]; pq.push(i); } } }
加粗的代码是未优化dijkstra所没有的。
每次更新结点,都把新的结点存到优先队列中去。
用一道例题练手。OJ链接:Travel Plan
AC代码:
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 1010 #define MAX (1<<30)-1 #define V vector<int> using namespace std; int g_dist[LEN][LEN]; int g_cost[LEN][LEN]; int vis[LEN]; int dist[LEN]; int cost[LEN]; int pre[LEN]; struct cmp{ bool operator () (int a,int b){ return dist[a]>dist[b]; } }; priority_queue<int,vector<int>,cmp> pq; int main(){ // freopen("1030.txt","r",stdin); int n,m,s,e,i,j,a,b,c,d,t; I("%d%d%d%d",&n,&m,&s,&e); fill(g_dist[0],g_dist[0]+LEN*LEN,MAX); FF(i,m){ I("%d%d%d%d",&a,&b,&c,&d); g_dist[a][b]=c; g_dist[b][a]=c; g_cost[a][b]=d; g_cost[b][a]=d; } fill(dist,dist+LEN,MAX); fill(cost,cost+LEN,MAX); cost[s]=0; pre[s]=-1; //加入堆优化 pq.push(s); //源点入队 dist[s]=0; while(!pq.empty()){ int u=pq.top(); pq.pop(); if(vis[u]) continue; vis[u]=1; FF(i,n) if(!vis[i]){ if(dist[u]+g_dist[u][i]<dist[i] || (dist[u]+g_dist[u][i]==dist[i] && cost[u]+g_cost[u][i]<cost[i])){ dist[i]=dist[u]+g_dist[u][i]; cost[i]=cost[u]+g_cost[u][i]; pre[i]=u; //如果通过u点更新了一个i点,那么i点入队。 pq.push(i); } } } vector<int> path; i=e; while(i!=-1){ path.insert(path.begin(),i); i=pre[i]; } FF(i,path.size()) O("%d ",path[i]); printf("%d %d\n",dist[e],cost[e]) ; return 0; }